diff --git a/setup_nuvolacdk.sh b/setup_nuvolacdk.sh index 48a00ac6..6b5da56f 100644 --- a/setup_nuvolacdk.sh +++ b/setup_nuvolacdk.sh @@ -15,6 +15,8 @@ else export DATADIR="/app/share" export DIORITE_TESTGEN="$DIORITE_PATH/testgen.py" export GI_TYPELIB_PATH="$PWD/build:$PWD/build/engineio-soup/src:$DIORITE_PATH/build:$GI_TYPELIB_PATH" + export CEF_SUBPROCESS_PATH="$VALACEF_PATH/build/ValacefSubprocess" + export NUVOLA_USE_CEF="true" fi if [ ! -f web_apps/test/unit.js ] diff --git a/src/nuvolakit-runner/AppRunnerController.vala b/src/nuvolakit-runner/AppRunnerController.vala index 15b2bc2d..d4c1d9e1 100644 --- a/src/nuvolakit-runner/AppRunnerController.vala +++ b/src/nuvolakit-runner/AppRunnerController.vala @@ -215,6 +215,11 @@ public class AppRunnerController: Drtgtk.Application config = new Config(app_storage.config_dir.get_child("config.json"), default_config); config.changed.connect(on_config_changed); gtk_settings.gtk_application_prefer_dark_theme = config.get_bool(ConfigKey.DARK_THEME); + #if HAVE_CEF + if (Environment.get_variable("NUVOLA_USE_CEF") == "true") { + assert(WebOptions.set_default(typeof(CefOptions))); + } + #endif } private bool init_ipc(StartupCheck startup_check) diff --git a/src/nuvolakit-runner/cef/CefEngine.vala b/src/nuvolakit-runner/cef/CefEngine.vala new file mode 100644 index 00000000..5c22399a --- /dev/null +++ b/src/nuvolakit-runner/cef/CefEngine.vala @@ -0,0 +1,180 @@ +/* + * Copyright 2014-2017 Jiří Janoušek + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CEF +namespace Nuvola { + +public class CefEngine : WebEngine { + private const string ZOOM_LEVEL_CONF = "webview.zoom_level"; + + public override Gtk.Widget get_main_web_view(){return web_view;} + public override bool get_web_plugins(){return ((CefOptions) options).flash_enabled;} + public override void set_web_plugins(bool enabled){} + public override void set_media_source_extension (bool enabled){} + public override bool get_media_source_extension(){return true;} + + private AppRunnerController runner_app; + private CefGtk.WebContext web_context; + private CefGtk.WebView web_view; + private JsEnvironment? env = null; + private JSApi api; + private IpcBus ipc_bus = null; + private Config config; + private Drt.KeyValueStorage session; + + public CefEngine(CefOptions web_options) { + base(web_options); + web_context = web_options.default_context; + } + + public override void early_init(AppRunnerController runner_app, IpcBus ipc_bus, + WebApp web_app, Config config, Connection? connection, HashTable worker_data) { + this.ipc_bus = ipc_bus; + this.runner_app = runner_app; + this.web_app = web_app; + this.config = config; + this.web_worker = new RemoteWebWorker(ipc_bus); + + worker_data["NUVOLA_API_ROUTER_TOKEN"] = ipc_bus.router.hex_token; + worker_data["WEBKITGTK_MAJOR"] = WebKit.get_major_version(); + worker_data["WEBKITGTK_MINOR"] = WebKit.get_minor_version(); + worker_data["WEBKITGTK_MICRO"] = WebKit.get_micro_version(); + worker_data["LIBSOUP_MAJOR"] = Soup.get_major_version(); + worker_data["LIBSOUP_MINOR"] = Soup.get_minor_version(); + worker_data["LIBSOUP_MICRO"] = Soup.get_micro_version(); + + web_view = new CefGtk.WebView(web_context); + load_uri("https://github.com/tiliado/valacef"); + } + + ~CefEngine() { + } + + public override void init() { + warning("Not implemented: init()"); + } + + public override void init_app_runner() { + warning("Not implemented: init_app_runner()"); + } + + public override void load_app() { + go_home(); + } + + public override void go_home() { + try { + var url = env.send_data_request_string("HomePageRequest", "url"); + if (url == null) { + runner_app.fatal_error("Invalid home page URL", "The web app integration script has provided an empty home page URL."); + } else if (!load_uri(url)) { + runner_app.fatal_error("Invalid home page URL", "The web app integration script has not provided a valid home page URL '%s'.".printf(url)); + } + } catch (GLib.Error e) { + runner_app.fatal_error("Initialization error", "%s failed to retrieve a home page of a web app. Initialization exited with error:\n\n%s".printf(runner_app.app_name, e.message)); + } + } + + public override void apply_network_proxy(Connection connection) { + warning("Not implemented: apply_network_proxy()"); + } + + public override string? get_url() { + return web_view != null ? web_view.uri : null; + } + + public override void load_url(string url) { + load_uri(url); + } + + private bool load_uri(string uri) { + if (uri.has_prefix("http://") || uri.has_prefix("https://")) { + web_view.load_uri(uri); + return true; + } + if (uri.has_prefix("nuvola://")) { + web_view.load_uri(web_app.data_dir.get_child(uri.substring(9)).get_uri()); + return true; + } + if (uri.has_prefix(web_app.data_dir.get_uri())) { + web_view.load_uri(uri); + return true; + } + return false; + } + + public override void go_back() { + web_view.go_back(); + } + + public override void go_forward() { + web_view.go_forward(); + } + + public override void reload() { + web_view.reload(); + } + + public override void zoom_in() { + web_view.zoom_in(); + } + + public override void zoom_out() { + web_view.zoom_out(); + } + + public override void zoom_reset() { + web_view.zoom_reset(); + } + + public override void set_user_agent(string? user_agent) { + warning("Not implemented: set_user_agent(%s)", user_agent); + } + + public override void get_preferences(out Variant values, out Variant entries) { + var args = new Variant("(s@a{sv}@av)", "PreferencesForm", + new Variant.array(new VariantType("{sv}"), {}), new Variant.array(VariantType.VARIANT, {})); + try { + env.call_function_sync("Nuvola.core.emit", ref args); + } catch (GLib.Error e) { + runner_app.show_error("Integration error", "%s failed to load preferences with error:\n\n%s".printf( + runner_app.app_name, e.message)); + } + args.get("(s@a{smv}@av)", null, out values, out entries); + } + + public override void call_function_sync(string name, ref Variant? params, bool propagate_error=false) + throws GLib.Error { + warning("Not implemented: call_function_sync(%s)", name); + } + + private void register_ipc_handlers() { + assert(ipc_bus != null); + var router = ipc_bus.router; + warning("Not implemented: register_ipc_handlers()"); + } +} + +} // namespace Nuvola +#endif diff --git a/src/nuvolakit-runner/cef/CefOptions.vala b/src/nuvolakit-runner/cef/CefOptions.vala new file mode 100644 index 00000000..ae963afa --- /dev/null +++ b/src/nuvolakit-runner/cef/CefOptions.vala @@ -0,0 +1,52 @@ +/* + * Copyright 2014-2017 Jiří Janoušek + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CEF +namespace Nuvola { + +public class CefOptions : WebOptions { + public override VersionTuple engine_version {get; protected set;} + public CefGtk.WebContext default_context{get; private set; default = null;} + public bool widevine_enabled {get; set; default = true;} + public bool flash_enabled {get; set; default = true;} + + public CefOptions(WebAppStorage storage) { + base(storage); + engine_version = VersionTuple.parse(Cef.get_chromium_version()); + } + + construct { + } + + public override WebEngine create_web_engine() { + if (default_context == null) { + CefGtk.init(widevine_enabled, flash_enabled); + default_context = new CefGtk.WebContext(GLib.Environment.get_user_config_dir() + "/cefium"); + } + return new CefEngine(this); + } +} + +} // namespace Nuvola +#endif