| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2020 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 -    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 - 
 -    End User License Agreement: www.juce.com/juce-6-licence
 -    Privacy Policy: www.juce.com/juce-privacy-policy
 - 
 -    Or: You may also use this code under the terms of the GPL v3 (see
 -    www.gnu.org/licenses).
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - 
 - //==============================================================================
 - class WebKitSymbols  : public DeletedAtShutdown
 - {
 - public:
 -     //==============================================================================
 -     bool isWebKitAvailable() const noexcept  { return webKitIsAvailable; }
 - 
 -     //==============================================================================
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_settings_new, juce_webkit_settings_new,
 -                                          (), WebKitSettings*)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_settings_set_hardware_acceleration_policy, juce_webkit_settings_set_hardware_acceleration_policy,
 -                                          (WebKitSettings*, int), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_new_with_settings, juce_webkit_web_view_new_with_settings,
 -                                          (WebKitSettings*), GtkWidget*)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_load_uri, juce_webkit_web_view_load_uri,
 -                                          (WebKitWebView*, const gchar*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_policy_decision_use, juce_webkit_policy_decision_use,
 -                                          (WebKitPolicyDecision*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_policy_decision_ignore, juce_webkit_policy_decision_ignore,
 -                                          (WebKitPolicyDecision*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_go_back, juce_webkit_web_view_go_back,
 -                                          (WebKitWebView*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_go_forward, juce_webkit_web_view_go_forward,
 -                                          (WebKitWebView*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_reload, juce_webkit_web_view_reload,
 -                                          (WebKitWebView*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_stop_loading, juce_webkit_web_view_stop_loading,
 -                                          (WebKitWebView*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_uri_request_get_uri, juce_webkit_uri_request_get_uri,
 -                                          (WebKitURIRequest*), const gchar*)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_navigation_action_get_request, juce_webkit_navigation_action_get_request,
 -                                          (WebKitNavigationAction*), WebKitURIRequest*)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_navigation_policy_decision_get_frame_name, juce_webkit_navigation_policy_decision_get_frame_name,
 -                                          (WebKitNavigationPolicyDecision*), const gchar*)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_navigation_policy_decision_get_navigation_action, juce_webkit_navigation_policy_decision_get_navigation_action,
 -                                          (WebKitNavigationPolicyDecision*), WebKitNavigationAction*)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (webkit_web_view_get_uri, juce_webkit_web_view_get_uri,
 -                                          (WebKitWebView*), const gchar*)
 - 
 -     //==============================================================================
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (gtk_init, juce_gtk_init,
 -                                          (int*, char***), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (gtk_plug_new, juce_gtk_plug_new,
 -                                          (::Window), GtkWidget*)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (gtk_scrolled_window_new, juce_gtk_scrolled_window_new,
 -                                          (GtkAdjustment*, GtkAdjustment*), GtkWidget*)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (gtk_container_add, juce_gtk_container_add,
 -                                          (GtkContainer*, GtkWidget*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (gtk_widget_show_all, juce_gtk_widget_show_all,
 -                                          (GtkWidget*), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (gtk_plug_get_id, juce_gtk_plug_get_id,
 -                                          (GtkPlug*), ::Window)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (gtk_main, juce_gtk_main,
 -                                          (), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (gtk_main_quit, juce_gtk_main_quit,
 -                                          (), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (g_unix_fd_add, juce_g_unix_fd_add,
 -                                          (gint, GIOCondition, GUnixFDSourceFunc, gpointer), guint)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (g_object_ref, juce_g_object_ref,
 -                                          (gpointer), gpointer)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (g_object_unref, juce_g_object_unref,
 -                                          (gpointer), void)
 - 
 -     JUCE_GENERATE_FUNCTION_WITH_DEFAULT (g_signal_connect_data, juce_g_signal_connect_data,
 -                                          (gpointer, const gchar*, GCallback, gpointer, GClosureNotify, GConnectFlags), gulong)
 - 
 -     //==============================================================================
 -     JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (WebKitSymbols)
 - 
 - private:
 -     WebKitSymbols() = default;
 - 
 -     ~WebKitSymbols()
 -     {
 -         clearSingletonInstance();
 -     }
 - 
 -     template <typename FuncPtr>
 -     struct SymbolBinding
 -     {
 -         FuncPtr& func;
 -         const char* name;
 -     };
 - 
 -     template <typename FuncPtr>
 -     SymbolBinding<FuncPtr> makeSymbolBinding (FuncPtr& func, const char* name)
 -     {
 -         return { func, name };
 -     }
 - 
 -     template <typename FuncPtr>
 -     bool loadSymbols (DynamicLibrary& lib, SymbolBinding<FuncPtr> binding)
 -     {
 -         if (auto* func = lib.getFunction (binding.name))
 -         {
 -             binding.func = reinterpret_cast<FuncPtr> (func);
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     template <typename FuncPtr, typename... Args>
 -     bool loadSymbols (DynamicLibrary& lib, SymbolBinding<FuncPtr> binding, Args... args)
 -     {
 -         return loadSymbols (lib, binding) && loadSymbols (lib, args...);
 -     }
 - 
 -     //==============================================================================
 -     bool loadWebkitSymbols()
 -     {
 -         return loadSymbols (webkitLib,
 -                             makeSymbolBinding (juce_webkit_settings_new,                                     "webkit_settings_new"),
 -                             makeSymbolBinding (juce_webkit_settings_set_hardware_acceleration_policy,        "webkit_settings_set_hardware_acceleration_policy"),
 -                             makeSymbolBinding (juce_webkit_web_view_new_with_settings,                       "webkit_web_view_new_with_settings"),
 -                             makeSymbolBinding (juce_webkit_policy_decision_use,                              "webkit_policy_decision_use"),
 -                             makeSymbolBinding (juce_webkit_policy_decision_ignore,                           "webkit_policy_decision_ignore"),
 -                             makeSymbolBinding (juce_webkit_web_view_go_back,                                 "webkit_web_view_go_back"),
 -                             makeSymbolBinding (juce_webkit_web_view_go_forward,                              "webkit_web_view_go_forward"),
 -                             makeSymbolBinding (juce_webkit_web_view_reload,                                  "webkit_web_view_reload"),
 -                             makeSymbolBinding (juce_webkit_web_view_stop_loading,                            "webkit_web_view_stop_loading"),
 -                             makeSymbolBinding (juce_webkit_uri_request_get_uri,                              "webkit_uri_request_get_uri"),
 -                             makeSymbolBinding (juce_webkit_web_view_load_uri,                                "webkit_web_view_load_uri"),
 -                             makeSymbolBinding (juce_webkit_navigation_action_get_request,                    "webkit_navigation_action_get_request"),
 -                             makeSymbolBinding (juce_webkit_navigation_policy_decision_get_frame_name,        "webkit_navigation_policy_decision_get_frame_name"),
 -                             makeSymbolBinding (juce_webkit_navigation_policy_decision_get_navigation_action, "webkit_navigation_policy_decision_get_navigation_action"),
 -                             makeSymbolBinding (juce_webkit_web_view_get_uri,                                 "webkit_web_view_get_uri"));
 -     }
 - 
 -     bool loadGtkSymbols()
 -     {
 -         return loadSymbols (gtkLib,
 -                             makeSymbolBinding (juce_gtk_init,                "gtk_init"),
 -                             makeSymbolBinding (juce_gtk_plug_new,            "gtk_plug_new"),
 -                             makeSymbolBinding (juce_gtk_scrolled_window_new, "gtk_scrolled_window_new"),
 -                             makeSymbolBinding (juce_gtk_container_add,       "gtk_container_add"),
 -                             makeSymbolBinding (juce_gtk_widget_show_all,     "gtk_widget_show_all"),
 -                             makeSymbolBinding (juce_gtk_plug_get_id,         "gtk_plug_get_id"),
 -                             makeSymbolBinding (juce_gtk_main,                "gtk_main"),
 -                             makeSymbolBinding (juce_gtk_main_quit,           "gtk_main_quit"),
 -                             makeSymbolBinding (juce_g_unix_fd_add,           "g_unix_fd_add"),
 -                             makeSymbolBinding (juce_g_object_ref,            "g_object_ref"),
 -                             makeSymbolBinding (juce_g_object_unref,          "g_object_unref"),
 -                             makeSymbolBinding (juce_g_signal_connect_data,   "g_signal_connect_data"));
 -     }
 - 
 -     //==============================================================================
 -     DynamicLibrary gtkLib { "libgtk-3.so" }, webkitLib { "libwebkit2gtk-4.0.so" };
 -     const bool webKitIsAvailable = loadWebkitSymbols() && loadGtkSymbols();
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebKitSymbols)
 - };
 - 
 - JUCE_IMPLEMENT_SINGLETON (WebKitSymbols)
 - 
 - //==============================================================================
 - extern int juce_gtkWebkitMain (int argc, const char* argv[]);
 - 
 - class CommandReceiver
 - {
 - public:
 -     struct Responder
 -     {
 -         virtual ~Responder() {}
 - 
 -         virtual void handleCommand (const String& cmd, const var& param) = 0;
 -         virtual void receiverHadError() = 0;
 -     };
 - 
 -     CommandReceiver (Responder* responderToUse, int inputChannelToUse)
 -         : responder (responderToUse), inChannel (inputChannelToUse)
 -     {
 -         setBlocking (inChannel, false);
 -     }
 - 
 -     static void setBlocking (int fd, bool shouldBlock)
 -     {
 -         auto flags = fcntl (fd, F_GETFL);
 -         fcntl (fd, F_SETFL, (shouldBlock ? (flags & ~O_NONBLOCK)
 -                                          : (flags | O_NONBLOCK)));
 -     }
 - 
 -     int getFd() const     { return inChannel; }
 - 
 -     void tryNextRead()
 -     {
 -         for (;;)
 -         {
 -             auto len = (receivingLength ? sizeof (size_t) : bufferLength.len);
 - 
 -             if (! receivingLength)
 -                 buffer.realloc (len);
 - 
 -             auto* dst = (receivingLength ? bufferLength.data : buffer.getData());
 - 
 -             auto actual = read (inChannel, &dst[pos], static_cast<size_t> (len - pos));
 - 
 -             if (actual < 0)
 -             {
 -                 if (errno == EINTR)
 -                     continue;
 - 
 -                 break;
 -             }
 - 
 -             pos += static_cast<size_t> (actual);
 - 
 -             if (pos == len)
 -             {
 -                 pos = 0;
 - 
 -                 if (! receivingLength)
 -                     parseJSON (String (buffer.getData(), bufferLength.len));
 - 
 -                 receivingLength = (! receivingLength);
 -             }
 -         }
 - 
 -         if (errno != EAGAIN && errno != EWOULDBLOCK && responder != nullptr)
 -             responder->receiverHadError();
 -     }
 - 
 -     static void sendCommand (int outChannel, const String& cmd, const var& params)
 -     {
 -         DynamicObject::Ptr obj = new DynamicObject;
 - 
 -         obj->setProperty (getCmdIdentifier(), cmd);
 - 
 -         if (! params.isVoid())
 -             obj->setProperty (getParamIdentifier(), params);
 - 
 -         auto json = JSON::toString (var (obj.get()));
 - 
 -         auto jsonLength = static_cast<size_t> (json.length());
 -         auto len        = sizeof (size_t) + jsonLength;
 - 
 -         HeapBlock<char> buffer (len);
 -         auto* dst = buffer.getData();
 - 
 -         memcpy (dst, &jsonLength, sizeof (size_t));
 -         dst += sizeof (size_t);
 - 
 -         memcpy (dst, json.toRawUTF8(), jsonLength);
 - 
 -         ssize_t ret;
 - 
 -         for (;;)
 -         {
 -             ret = write (outChannel, buffer.getData(), len);
 - 
 -             if (ret != -1 || errno != EINTR)
 -                 break;
 -         }
 -     }
 - 
 - private:
 -     void parseJSON (const String& json)
 -     {
 -         auto object = JSON::fromString (json);
 - 
 -         if (! object.isVoid())
 -         {
 -             auto cmd    = object.getProperty (getCmdIdentifier(),   {}).toString();
 -             auto params = object.getProperty (getParamIdentifier(), {});
 - 
 -             if (responder != nullptr)
 -                 responder->handleCommand (cmd, params);
 -         }
 -     }
 - 
 -     static Identifier getCmdIdentifier()    { static Identifier Id ("cmd");    return Id; }
 -     static Identifier getParamIdentifier()  { static Identifier Id ("params"); return Id; }
 - 
 -     Responder* responder = nullptr;
 -     int inChannel = 0;
 -     size_t pos = 0;
 -     bool receivingLength = true;
 -     union { char data [sizeof (size_t)]; size_t len; } bufferLength;
 -     HeapBlock<char> buffer;
 - };
 - 
 - #define juce_g_signal_connect(instance, detailed_signal, c_handler, data) \
 -     WebKitSymbols::getInstance()->juce_g_signal_connect_data (instance, detailed_signal, c_handler, data, nullptr, (GConnectFlags) 0)
 - 
 - //==============================================================================
 - class GtkChildProcess : private CommandReceiver::Responder
 - {
 - public:
 -     //==============================================================================
 -     GtkChildProcess (int inChannel, int outChannelToUse)
 -         : outChannel (outChannelToUse),
 -           receiver (this, inChannel)
 -     {}
 - 
 -     int entry()
 -     {
 -         CommandReceiver::setBlocking (outChannel, true);
 - 
 -         WebKitSymbols::getInstance()->juce_gtk_init (nullptr, nullptr);
 - 
 -         auto* settings = WebKitSymbols::getInstance()->juce_webkit_settings_new();
 -         WebKitSymbols::getInstance()->juce_webkit_settings_set_hardware_acceleration_policy (settings,
 -                                                                                              /* WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER */ 2);
 - 
 -         auto* plug      = WebKitSymbols::getInstance()->juce_gtk_plug_new (0);
 -         auto* container = WebKitSymbols::getInstance()->juce_gtk_scrolled_window_new (nullptr, nullptr);
 - 
 -         auto* webviewWidget = WebKitSymbols::getInstance()->juce_webkit_web_view_new_with_settings (settings);
 -         webview = (WebKitWebView*) webviewWidget;
 - 
 -         WebKitSymbols::getInstance()->juce_gtk_container_add ((GtkContainer*) container, webviewWidget);
 -         WebKitSymbols::getInstance()->juce_gtk_container_add ((GtkContainer*) plug,      container);
 - 
 -         WebKitSymbols::getInstance()->juce_webkit_web_view_load_uri (webview, "about:blank");
 - 
 -         juce_g_signal_connect (webview, "decide-policy",
 -                                (GCallback) decidePolicyCallback, this);
 - 
 -         juce_g_signal_connect (webview, "load-changed",
 -                                (GCallback) loadChangedCallback, this);
 - 
 -         juce_g_signal_connect (webview, "load-failed",
 -                                (GCallback) loadFailedCallback, this);
 - 
 -         WebKitSymbols::getInstance()->juce_gtk_widget_show_all (plug);
 -         auto wID = (unsigned long) WebKitSymbols::getInstance()->juce_gtk_plug_get_id ((GtkPlug*) plug);
 - 
 -         ssize_t ret;
 - 
 -         for (;;)
 -         {
 -             ret = write (outChannel, &wID, sizeof (wID));
 - 
 -             if (ret != -1 || errno != EINTR)
 -                 break;
 -         }
 - 
 -         WebKitSymbols::getInstance()->juce_g_unix_fd_add (receiver.getFd(), G_IO_IN, pipeReadyStatic, this);
 -         receiver.tryNextRead();
 - 
 -         WebKitSymbols::getInstance()->juce_gtk_main();
 - 
 -         WebKitSymbols::getInstance()->deleteInstance();
 -         return 0;
 -     }
 - 
 -     void goToURL (const var& params)
 -     {
 -         static Identifier urlIdentifier ("url");
 -         auto url = params.getProperty (urlIdentifier, var()).toString();
 - 
 -         WebKitSymbols::getInstance()->juce_webkit_web_view_load_uri (webview, url.toRawUTF8());
 -     }
 - 
 -     void handleDecisionResponse (const var& params)
 -     {
 -         auto* decision = (WebKitPolicyDecision*) ((int64) params.getProperty ("decision_id", var (0)));
 -         bool allow = params.getProperty ("allow", var (false));
 - 
 -         if (decision != nullptr && decisions.contains (decision))
 -         {
 -             if (allow)
 -                 WebKitSymbols::getInstance()->juce_webkit_policy_decision_use (decision);
 -             else
 -                 WebKitSymbols::getInstance()->juce_webkit_policy_decision_ignore (decision);
 - 
 -             decisions.removeAllInstancesOf (decision);
 -             WebKitSymbols::getInstance()->juce_g_object_unref (decision);
 -         }
 -     }
 - 
 -     //==============================================================================
 -     void handleCommand (const String& cmd, const var& params) override
 -     {
 -         if      (cmd == "quit")      quit();
 -         else if (cmd == "goToURL")   goToURL (params);
 -         else if (cmd == "goBack")    WebKitSymbols::getInstance()->juce_webkit_web_view_go_back      (webview);
 -         else if (cmd == "goForward") WebKitSymbols::getInstance()->juce_webkit_web_view_go_forward   (webview);
 -         else if (cmd == "refresh")   WebKitSymbols::getInstance()->juce_webkit_web_view_reload       (webview);
 -         else if (cmd == "stop")      WebKitSymbols::getInstance()->juce_webkit_web_view_stop_loading (webview);
 -         else if (cmd == "decision")  handleDecisionResponse (params);
 -     }
 - 
 -     void receiverHadError() override
 -     {
 -         exit (-1);
 -     }
 - 
 -     //==============================================================================
 -     bool pipeReady (gint fd, GIOCondition)
 -     {
 -         if (fd == receiver.getFd())
 -         {
 -             receiver.tryNextRead();
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     void quit()
 -     {
 -         WebKitSymbols::getInstance()->juce_gtk_main_quit();
 -     }
 - 
 -     String getURIStringForAction (WebKitNavigationAction* action)
 -     {
 -         auto* request = WebKitSymbols::getInstance()->juce_webkit_navigation_action_get_request (action);
 -         return WebKitSymbols::getInstance()->juce_webkit_uri_request_get_uri (request);
 -     }
 - 
 -     bool onNavigation (String frameName,
 -                        WebKitNavigationAction* action,
 -                        WebKitPolicyDecision* decision)
 -     {
 -         if (decision != nullptr && frameName.isEmpty())
 -         {
 -             WebKitSymbols::getInstance()->juce_g_object_ref (decision);
 -             decisions.add (decision);
 - 
 -             DynamicObject::Ptr params = new DynamicObject;
 - 
 -             params->setProperty ("url", getURIStringForAction (action));
 -             params->setProperty ("decision_id", (int64) decision);
 -             CommandReceiver::sendCommand (outChannel, "pageAboutToLoad", var (params.get()));
 - 
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     bool onNewWindow (String /*frameName*/,
 -                       WebKitNavigationAction* action,
 -                       WebKitPolicyDecision* decision)
 -     {
 -         if (decision != nullptr)
 -         {
 -             DynamicObject::Ptr params = new DynamicObject;
 - 
 -             params->setProperty ("url", getURIStringForAction (action));
 -             CommandReceiver::sendCommand (outChannel, "newWindowAttemptingToLoad", var (params.get()));
 - 
 -             // never allow new windows
 -             WebKitSymbols::getInstance()->juce_webkit_policy_decision_ignore (decision);
 - 
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     void onLoadChanged (WebKitLoadEvent loadEvent)
 -     {
 -         if (loadEvent == WEBKIT_LOAD_FINISHED)
 -         {
 -             DynamicObject::Ptr params = new DynamicObject;
 - 
 -             params->setProperty ("url", String (WebKitSymbols::getInstance()->juce_webkit_web_view_get_uri (webview)));
 -             CommandReceiver::sendCommand (outChannel, "pageFinishedLoading", var (params.get()));
 -         }
 -     }
 - 
 -     bool onDecidePolicy (WebKitPolicyDecision*    decision,
 -                          WebKitPolicyDecisionType decisionType)
 -     {
 -         switch (decisionType)
 -         {
 -         case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
 -             {
 -                 auto* navigationDecision = (WebKitNavigationPolicyDecision*) decision;
 -                 auto* frameName = WebKitSymbols::getInstance()->juce_webkit_navigation_policy_decision_get_frame_name (navigationDecision);
 - 
 -                 return onNavigation (String (frameName != nullptr ? frameName : ""),
 -                                      WebKitSymbols::getInstance()->juce_webkit_navigation_policy_decision_get_navigation_action (navigationDecision),
 -                                      decision);
 -             }
 -             break;
 -         case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
 -             {
 -                 auto* navigationDecision = (WebKitNavigationPolicyDecision*) decision;
 -                 auto* frameName = WebKitSymbols::getInstance()->juce_webkit_navigation_policy_decision_get_frame_name (navigationDecision);
 - 
 -                 return onNewWindow  (String (frameName != nullptr ? frameName : ""),
 -                                      WebKitSymbols::getInstance()->juce_webkit_navigation_policy_decision_get_navigation_action (navigationDecision),
 -                                      decision);
 -             }
 -             break;
 -         case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
 -             {
 -                 auto* response = (WebKitNavigationPolicyDecision*) decision;
 - 
 -                 // for now just always allow response requests
 -                 ignoreUnused (response);
 -                 WebKitSymbols::getInstance()->juce_webkit_policy_decision_use (decision);
 -                 return true;
 -             }
 -             break;
 -         default:
 -             break;
 -         }
 - 
 -         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.get()));
 -     }
 - 
 - private:
 -     static gboolean pipeReadyStatic (gint fd, GIOCondition condition, gpointer user)
 -     {
 -         return (reinterpret_cast<GtkChildProcess*> (user)->pipeReady (fd, condition) ? TRUE : FALSE);
 -     }
 - 
 -     static gboolean decidePolicyCallback (WebKitWebView*,
 -                                           WebKitPolicyDecision*    decision,
 -                                           WebKitPolicyDecisionType decisionType,
 -                                           gpointer user)
 -     {
 -         auto& owner = *reinterpret_cast<GtkChildProcess*> (user);
 -         return (owner.onDecidePolicy (decision, decisionType) ? TRUE : FALSE);
 -     }
 - 
 -     static void loadChangedCallback (WebKitWebView*,
 -                                      WebKitLoadEvent loadEvent,
 -                                      gpointer        user)
 -     {
 -         auto& owner = *reinterpret_cast<GtkChildProcess*> (user);
 -         owner.onLoadChanged (loadEvent);
 -     }
 - 
 -     static void loadFailedCallback (WebKitWebView*,
 -                                     WebKitLoadEvent /*loadEvent*/,
 -                                     gchar*          /*failing_uri*/,
 -                                     GError*         error,
 -                                     gpointer        user)
 -     {
 -         auto& owner = *reinterpret_cast<GtkChildProcess*> (user);
 -         owner.onLoadFailed (error);
 -     }
 - 
 -     int outChannel = 0;
 -     CommandReceiver receiver;
 -     WebKitWebView* webview = nullptr;
 -     Array<WebKitPolicyDecision*> decisions;
 - };
 - 
 - //==============================================================================
 - class WebBrowserComponent::Pimpl  : private Thread,
 -                                     private CommandReceiver::Responder
 - {
 - public:
 -     Pimpl (WebBrowserComponent& parent)
 -         : Thread ("Webview"), owner (parent)
 -     {
 -         webKitIsAvailable = WebKitSymbols::getInstance()->isWebKitAvailable();
 -     }
 - 
 -     ~Pimpl() override
 -     {
 -         quit();
 -     }
 - 
 -     //==============================================================================
 -     void init()
 -     {
 -         if (! webKitIsAvailable)
 -             return;
 - 
 -         launchChild();
 - 
 -         auto ret = pipe (threadControl);
 - 
 -         ignoreUnused (ret);
 -         jassert (ret == 0);
 - 
 -         CommandReceiver::setBlocking (inChannel,        true);
 -         CommandReceiver::setBlocking (outChannel,       true);
 -         CommandReceiver::setBlocking (threadControl[0], false);
 -         CommandReceiver::setBlocking (threadControl[1], true);
 - 
 -         unsigned long windowHandle;
 -         auto actual = read (inChannel, &windowHandle, sizeof (windowHandle));
 - 
 -         if (actual != (ssize_t) sizeof (windowHandle))
 -         {
 -             killChild();
 -             return;
 -         }
 - 
 -         receiver.reset (new CommandReceiver (this, inChannel));
 - 
 -         pfds.push_back ({ threadControl[0],  POLLIN, 0 });
 -         pfds.push_back ({ receiver->getFd(), POLLIN, 0 });
 - 
 -         startThread();
 - 
 -         xembed.reset (new XEmbedComponent (windowHandle));
 -         owner.addAndMakeVisible (xembed.get());
 -     }
 - 
 -     void quit()
 -     {
 -         if (! webKitIsAvailable)
 -             return;
 - 
 -         if (isThreadRunning())
 -         {
 -             signalThreadShouldExit();
 - 
 -             char ignore = 0;
 -             ssize_t ret;
 - 
 -             for (;;)
 -             {
 -                 ret = write (threadControl[1], &ignore, 1);
 - 
 -                 if (ret != -1 || errno != EINTR)
 -                     break;
 -             }
 - 
 -             waitForThreadToExit (-1);
 -             receiver = nullptr;
 -         }
 - 
 -         if (childProcess != 0)
 -         {
 -             CommandReceiver::sendCommand (outChannel, "quit", {});
 -             killChild();
 -         }
 -     }
 - 
 -     //==============================================================================
 -     void goToURL (const String& url, const StringArray* headers, const MemoryBlock* postData)
 -     {
 -         if (! webKitIsAvailable)
 -             return;
 - 
 -         DynamicObject::Ptr params = new DynamicObject;
 - 
 -         params->setProperty ("url", url);
 - 
 -         if (headers != nullptr)
 -             params->setProperty ("headers", var (*headers));
 - 
 -         if (postData != nullptr)
 -             params->setProperty ("postData", var (*postData));
 - 
 -         CommandReceiver::sendCommand (outChannel, "goToURL", var (params.get()));
 -     }
 - 
 -     void goBack()      { if (webKitIsAvailable) CommandReceiver::sendCommand (outChannel, "goBack",    {}); }
 -     void goForward()   { if (webKitIsAvailable) CommandReceiver::sendCommand (outChannel, "goForward", {}); }
 -     void refresh()     { if (webKitIsAvailable) CommandReceiver::sendCommand (outChannel, "refresh",   {}); }
 -     void stop()        { if (webKitIsAvailable) CommandReceiver::sendCommand (outChannel, "stop",      {}); }
 - 
 -     void resized()
 -     {
 -         if (xembed != nullptr)
 -             xembed->setBounds (owner.getLocalBounds());
 -     }
 - 
 - private:
 -     //==============================================================================
 -     void killChild()
 -     {
 -         if (childProcess != 0)
 -         {
 -             xembed = nullptr;
 - 
 -             int status = 0, result = 0;
 - 
 -             result = waitpid (childProcess, &status, WNOHANG);
 -             for (int i = 0; i < 15 && (! WIFEXITED(status) || result != childProcess); ++i)
 -             {
 -                 Thread::sleep (100);
 -                 result = waitpid (childProcess, &status, WNOHANG);
 -             }
 - 
 -             // clean-up any zombies
 -             status = 0;
 -             if (! WIFEXITED(status) || result != childProcess)
 -             {
 -                 for (;;)
 -                 {
 -                     kill (childProcess, SIGTERM);
 -                     waitpid (childProcess, &status, 0);
 - 
 -                     if (WIFEXITED (status))
 -                         break;
 -                 }
 -             }
 - 
 -             childProcess = 0;
 -         }
 -     }
 - 
 -     void launchChild()
 -     {
 -         int inPipe[2], outPipe[2];
 - 
 -         auto ret = pipe (inPipe);
 -         ignoreUnused (ret); jassert (ret == 0);
 - 
 -         ret = pipe (outPipe);
 -         ignoreUnused (ret); jassert (ret == 0);
 - 
 -         auto pid = fork();
 -         if (pid == 0)
 -         {
 -             close (inPipe[0]);
 -             close (outPipe[1]);
 - 
 -             HeapBlock<const char*> argv (5);
 -             StringArray arguments;
 - 
 -             arguments.add (File::getSpecialLocation (File::currentExecutableFile).getFullPathName());
 -             arguments.add ("--juce-gtkwebkitfork-child");
 -             arguments.add (String (outPipe[0]));
 -             arguments.add (String (inPipe [1]));
 - 
 -             for (int i = 0; i < arguments.size(); ++i)
 -                 argv[i] = arguments[i].toRawUTF8();
 - 
 -             argv[4] = nullptr;
 - 
 -            #if JUCE_STANDALONE_APPLICATION
 -             execv (arguments[0].toRawUTF8(), (char**) argv.getData());
 -            #else
 -             juce_gtkWebkitMain (4, (const char**) argv.getData());
 -            #endif
 -             exit (0);
 -         }
 - 
 -         close (inPipe[1]);
 -         close (outPipe[0]);
 - 
 -         inChannel  = inPipe[0];
 -         outChannel = outPipe[1];
 - 
 -         childProcess = pid;
 -     }
 - 
 -     void run() override
 -     {
 -         while (! threadShouldExit())
 -         {
 -             if (shouldExit())
 -                 return;
 - 
 -             receiver->tryNextRead();
 - 
 -             int result = 0;
 - 
 -             while (result == 0 || (result < 0 && errno == EINTR))
 -                 result = poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), 0);
 - 
 -             if (result < 0)
 -                 break;
 -         }
 -     }
 - 
 -     bool shouldExit()
 -     {
 -         char ignore;
 -         auto result = read (threadControl[0], &ignore, 1);
 - 
 -         return (result != -1 || (errno != EAGAIN && errno != EWOULDBLOCK));
 -     }
 - 
 -     //==============================================================================
 -     void handleCommandOnMessageThread (const String& cmd, const var& params)
 -     {
 -         auto url = params.getProperty ("url", var()).toString();
 - 
 -         if      (cmd == "pageAboutToLoad")           handlePageAboutToLoad (url, params);
 -         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();
 -     }
 - 
 -     void handlePageAboutToLoad (const String& url, const var& inputParams)
 -     {
 -         int64 decision_id = inputParams.getProperty ("decision_id", var (0));
 - 
 -         if (decision_id != 0)
 -         {
 -             DynamicObject::Ptr params = new DynamicObject;
 - 
 -             params->setProperty ("decision_id", decision_id);
 -             params->setProperty ("allow", owner.pageAboutToLoad (url));
 - 
 -             CommandReceiver::sendCommand (outChannel, "decision", var (params.get()));
 -         }
 -     }
 - 
 -     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();
 - 
 -         (new HandleOnMessageThread (this, cmd, params))->post();
 - 
 -         // wait until the command has executed on the message thread
 -         // this ensures that Pimpl can never be deleted while the
 -         // message has not been executed yet
 -         threadBlocker.wait (-1);
 -     }
 - 
 -     void receiverHadError() override {}
 - 
 -     //==============================================================================
 -     struct HandleOnMessageThread : public CallbackMessage
 -     {
 -         HandleOnMessageThread (Pimpl* pimpl, const String& cmdToUse, const var& params)
 -             : owner (pimpl), cmdToSend (cmdToUse), paramsToSend (params)
 -         {}
 - 
 -         void messageCallback() override
 -         {
 -             owner->handleCommandOnMessageThread (cmdToSend, paramsToSend);
 -         }
 - 
 -         Pimpl* owner = nullptr;
 -         String cmdToSend;
 -         var paramsToSend;
 -     };
 - 
 -     bool webKitIsAvailable = false;
 - 
 -     WebBrowserComponent& owner;
 -     std::unique_ptr<CommandReceiver> receiver;
 -     int childProcess = 0, inChannel = 0, outChannel = 0;
 -     int threadControl[2];
 -     std::unique_ptr<XEmbedComponent> xembed;
 -     WaitableEvent threadBlocker;
 -     std::vector<pollfd> pfds;
 - };
 - 
 - //==============================================================================
 - WebBrowserComponent::WebBrowserComponent (const bool unloadWhenHidden)
 -     : browser (new Pimpl (*this)),
 -       unloadPageWhenHidden (unloadWhenHidden)
 - {
 -     ignoreUnused (blankPageShown);
 -     ignoreUnused (unloadPageWhenHidden);
 - 
 -     setOpaque (true);
 - 
 -     browser->init();
 - }
 - 
 - WebBrowserComponent::~WebBrowserComponent()
 - {
 - }
 - 
 - //==============================================================================
 - void WebBrowserComponent::goToURL (const String& url,
 -                                    const StringArray* headers,
 -                                    const MemoryBlock* postData)
 - {
 -     lastURL = url;
 - 
 -     if (headers != nullptr)
 -         lastHeaders = *headers;
 -     else
 -         lastHeaders.clear();
 - 
 -     if (postData != nullptr)
 -         lastPostData = *postData;
 -     else
 -         lastPostData.reset();
 - 
 -     browser->goToURL (url, headers, postData);
 - }
 - 
 - void WebBrowserComponent::stop()
 - {
 -     browser->stop();
 - }
 - 
 - void WebBrowserComponent::goBack()
 - {
 -     lastURL.clear();
 - 
 -     browser->goBack();
 - }
 - 
 - void WebBrowserComponent::goForward()
 - {
 -     lastURL.clear();
 -     browser->goForward();
 - }
 - 
 - void WebBrowserComponent::refresh()
 - {
 -     browser->refresh();
 - }
 - 
 - //==============================================================================
 - void WebBrowserComponent::paint (Graphics& g)
 - {
 -     g.fillAll (Colours::white);
 - }
 - 
 - void WebBrowserComponent::checkWindowAssociation()
 - {
 - }
 - 
 - void WebBrowserComponent::reloadLastURL()
 - {
 -     if (lastURL.isNotEmpty())
 -     {
 -         goToURL (lastURL, &lastHeaders, &lastPostData);
 -         lastURL.clear();
 -     }
 - }
 - 
 - void WebBrowserComponent::parentHierarchyChanged()
 - {
 -     checkWindowAssociation();
 - }
 - 
 - void WebBrowserComponent::resized()
 - {
 -     if (browser != nullptr)
 -         browser->resized();
 - }
 - 
 - void WebBrowserComponent::visibilityChanged()
 - {
 -     checkWindowAssociation();
 - }
 - 
 - void WebBrowserComponent::focusGained (FocusChangeType)
 - {
 - }
 - 
 - void WebBrowserComponent::clearCookies()
 - {
 -     // Currently not implemented on linux as WebBrowserComponent currently does not
 -     // store cookies on linux
 -     jassertfalse;
 - }
 - 
 - int juce_gtkWebkitMain (int argc, const char* argv[])
 - {
 -     if (argc != 4)
 -         return -1;
 - 
 -     GtkChildProcess child (String (argv[2]).getIntValue(),
 -                            String (argv[3]).getIntValue());
 - 
 -     return child.entry();
 - }
 - 
 - } // namespace juce
 
 
  |