Permalink
Browse files

Start-up check selects suitable engine

- It is the first one that satisfies requirements
- Default engine is WebKitGTK+ unless --cef-default build flag is used.
- Issue: #372

Signed-off-by: Jiří Janoušek <janousek.jiri@gmail.com>
  • Loading branch information...
fenryxo committed Dec 30, 2017
1 parent dbf0335 commit f521fdfb59a8558b8a58a9d4dbbf8c2ef106d601
@@ -73,6 +73,7 @@ public class AppRunnerController: Drtgtk.Application
public WebApp web_app {get; protected set;}
public WebAppStorage app_storage {get; protected set;}
public string dbus_id {get; private set;}
private WebOptions[] available_web_options;
private WebOptions web_options;
private WebkitOptions webkit_options;
public WebEngine web_engine {get; private set;}
@@ -146,11 +147,11 @@ public class AppRunnerController: Drtgtk.Application
private void start() {
init_settings();
format_support = new FormatSupport(storage.require_data_file("audio/audiotest.mp3").get_path());
var startup_check = new StartupCheck(web_app, web_options, format_support);
var startup_check = new StartupCheck(web_app, format_support);
startup_window = new StartupWindow(this, startup_check);
startup_window.present();
startup_check.check_desktop_portal_available.begin((o, res) => startup_check.check_desktop_portal_available.end(res));
startup_check.check_app_requirements.begin((o, res) => startup_check.check_app_requirements.end(res));
startup_check.check_app_requirements.begin(available_web_options, (o, res) => startup_check.check_app_requirements.end(res));
startup_check.check_graphics_drivers.begin((o, res) => startup_check.check_graphics_drivers.end(res));
startup_check.task_finished.connect_after(on_startup_check_task_finished);
}
@@ -186,20 +187,19 @@ public class AppRunnerController: Drtgtk.Application
}
}
private void on_startup_window_ready_to_continue(StartupWindow window)
{
private void on_startup_window_ready_to_continue(StartupWindow window) {
var status = startup_window.model.final_status;
startup_window.ready_to_continue.disconnect(on_startup_window_ready_to_continue);
startup_window.destroy();
startup_window = null;
switch (status)
{
switch (status) {
case StartupCheck.Status.WARNING:
case StartupCheck.Status.OK:
web_options = startup_window.model.web_options;
init_gui();
init_web_engine();
break;
}
startup_window.destroy();
startup_window = null;
}
private void init_settings()
@@ -219,18 +219,22 @@ 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"
|| CEF_DEFAULT && Environment.get_variable("NUVOLA_USE_CEF") != "false") {
assert(WebOptions.set_default(typeof(CefOptions)));
available_web_options = {
WebOptions.create(typeof(CefOptions), app_storage),
WebOptions.create(typeof(WebkitOptions), app_storage)};
} else {
available_web_options = {
WebOptions.create(typeof(WebkitOptions), app_storage),
WebOptions.create(typeof(CefOptions), app_storage)};
}
#else
available_web_options = {WebOptions.create(typeof(WebkitOptions), app_storage)};
#endif
connection = new Connection(new Soup.Session(), app_storage.cache_dir.get_child("conn"), config);
if (!WebOptions.set_default(typeof(WebkitOptions))) {
warning("Default engine is %s.", WebOptions.get_default().name());
}
web_options = WebOptions.create_default(app_storage);
webkit_options = (web_options as WebkitOptions) ?? new WebkitOptions(app_storage);
}
private bool init_ipc(StartupCheck startup_check)
@@ -373,6 +377,8 @@ public class AppRunnerController: Drtgtk.Application
}
private void init_web_engine() {
webkit_options = (web_options as WebkitOptions) ?? new WebkitOptions(app_storage);
available_web_options = null;
web_engine = web_options.create_web_engine(web_app);
if (web_options.get_name() == "Chromium") {
show_info_bar("engine-warning", Gtk.MessageType.WARNING,
@@ -75,16 +75,16 @@ public class StartupCheck : GLib.Object
#endif
[Description (nick="Web App object", blurb="Currently loaded web application")]
public WebApp web_app {get; construct;}
public WebOptions web_options {get; construct;}
public WebOptions? web_options {get; private set; default = null;}
/**
* Create new StartupCheck object.
*
* @param web_app Web application to check its requirements.
* @param format_support Information about supported formats and technologies.
*/
public StartupCheck(WebApp web_app, WebOptions web_options, FormatSupport format_support) {
GLib.Object(format_support: format_support, web_app: web_app, web_options: web_options);
public StartupCheck(WebApp web_app, FormatSupport format_support) {
GLib.Object(format_support: format_support, web_app: web_app);
}
~StartupCheck() {
@@ -188,67 +188,110 @@ public class StartupCheck : GLib.Object
*
* The {@link app_requirements_status} property is populated with the result of this check.
*/
public async void check_app_requirements() {
public async void check_app_requirements(WebOptions[] available_web_options) {
const string NAME = "Web App Requirements";
task_started(NAME);
app_requirements_status = Status.IN_PROGRESS;
var result_status = Status.OK;
string? result_message = null;
try {
yield format_support.check();
} catch (GLib.Error e) {
result_message = e.message;
}
var webkit_options = web_options as WebkitOptions;
if (webkit_options != null) {
webkit_options.format_support = format_support;
var n_options = available_web_options.length;
assert(n_options > 0);
var checks = new WebOptionsCheck[n_options];
for (var i = 0; i < n_options; i++) {
var webkit_options = available_web_options[i] as WebkitOptions;
if (webkit_options != null) {
webkit_options.format_support = format_support;
}
checks[i] = new WebOptionsCheck(available_web_options[i], web_app);
}
var parser = new RequirementParser(web_options);
try {
parser.eval(web_app.requirements);
if (parser.n_unsupported > 0) {
result_status = Status.ERROR;
Drt.String.append(ref result_message, "\n", Markup.printf_escaped(
"This web app requires certain technologies to function properly but these requirements "
+ "have not been satisfied.\n\nFailed requirements: <i>%s</i>\n\n"
+ "<a href=\"%s\">Get help with installation</a>",
parser.failed_requirements ?? "", WEB_APP_REQUIREMENTS_HELP_URL));
} else if (parser.n_unknown > 0) {
yield web_options.gather_format_support_info(web_app);
parser.eval(web_app.requirements);
if (parser.n_unsupported + parser.n_unknown > 0) {
result_status = Status.ERROR;
Drt.String.append(ref result_message, "\n", Markup.printf_escaped(
"This web app requires certain technologies to function properly but these requirements "
+ "have not been satisfied.\n\nFailed requirements: <i>%s %s</i>\n\n"
+ "<a href=\"%s\">Get help with installation</a>",
parser.failed_requirements ?? "", parser.unknown_requirements ?? "", WEB_APP_REQUIREMENTS_HELP_URL));
/* The first pass: Perform requirements check for all web engines and asses the results. */
var n_engines_without_unsupported = 0;
foreach (var check in checks) {
try {
debug("Checking requirements with %s", check.web_options.get_name_version());
check.check_requirements();
if (check.parser.n_unsupported == 0) {
n_engines_without_unsupported++;
}
} catch (Drt.RequirementError e) {
Drt.String.append(ref result_message, "\n", Markup.printf_escaped(
"This web app provides invalid metadata about its requirements."
+ " Please create a bug report. The error message is: %s\n\n%s",
e.message, check.web_app.requirements));
check_app_requirements_finished(Status.ERROR, (owned) result_message, available_web_options);
return;
}
} catch (Drt.RequirementError e) {
}
/* If there is no engine without an unsupported requirement, abort early. */
if (n_engines_without_unsupported == 0) {
Drt.String.append(ref result_message, "\n", Markup.printf_escaped(
"This web app provides invalid metadata about its requirements."
+ " Please create a bug report. The error message is: %s\n\n%s",
e.message, web_app.requirements));
result_status = Status.ERROR;
"This web app requires certain technologies to function properly but these requirements "
+ "have not been satisfied.\n\nFailed requirements: <i>%s</i>\n\n"
+ "<a href=\"%s\">Get help with installation</a>",
checks[0].parser.failed_requirements ?? "", WEB_APP_REQUIREMENTS_HELP_URL));
check_app_requirements_finished(Status.ERROR, (owned) result_message, available_web_options);
return;
}
var warnings = web_options.get_format_support_warnings();
if (warnings.length > 0) {
if (result_status < Status.WARNING) {
result_status = Status.WARNING;
/* Select the first engine which satisfies requirements. */
foreach (var check in checks) {
if (check.parser.n_unsupported == 0) {
if (check.parser.n_unknown > 0) {
yield check.web_options.gather_format_support_info(check.web_app);
try {
debug("Checking requirements with %s", check.web_options.get_name_version());
check.check_requirements();
} catch (Drt.RequirementError e) {
Drt.String.append(ref result_message, "\n", Markup.printf_escaped(
"This web app provides invalid metadata about its requirements."
+ " Please create a bug report. The error message is: %s\n\n%s",
e.message, check.web_app.requirements));
check_app_requirements_finished(Status.ERROR, (owned) result_message, available_web_options);
return;
}
}
if (check.parser.n_unsupported + check.parser.n_unknown == 0) {
this.web_options = check.web_options;
check_app_requirements_finished(Status.OK, (owned) result_message, available_web_options);
return;
}
}
foreach (unowned string entry in warnings) {
Drt.String.append(ref result_message, "\n\n", entry);
}
/* No engine satisfies requirements */
Drt.String.append(ref result_message, "\n", Markup.printf_escaped(
"This web app requires certain technologies to function properly but these requirements "
+ "have not been satisfied.\n\nFailed requirements: <i>%s %s</i>\n\n"
+ "<a href=\"%s\">Get help with installation</a>",
checks[0].parser.failed_requirements ?? "", checks[0].parser.unknown_requirements ?? "",
WEB_APP_REQUIREMENTS_HELP_URL));
check_app_requirements_finished(Status.ERROR, (owned) result_message, available_web_options);
}
private void check_app_requirements_finished(Status status, owned string? message, WebOptions[] web_options) {
var msg = (owned) message;
foreach (var web_opt in web_options) {
var warnings = web_opt.get_format_support_warnings();
if (warnings.length > 0) {
if (status < Status.WARNING) {
status = Status.WARNING;
}
foreach (unowned string entry in warnings) {
Drt.String.append(ref msg, "\n\n", "%s: %s".printf(web_opt.get_name(), entry));
}
}
}
yield Drt.EventLoop.resume_later();
app_requirements_message = (owned) result_message;
app_requirements_status = result_status;
task_finished(NAME);
app_requirements_message = (owned) msg;
app_requirements_status = status;
task_finished("Web App Requirements");
}
/**
@@ -450,6 +493,22 @@ public class StartupCheck : GLib.Object
return {UNKNOWN, NOT_APPLICABLE, IN_PROGRESS, OK, WARNING, ERROR};
}
}
private class WebOptionsCheck {
public WebOptions web_options;
public RequirementParser parser;
public WebApp web_app;
public WebOptionsCheck(WebOptions web_options, WebApp web_app) {
this.web_options = web_options;
this.parser = new RequirementParser(web_options);
this.web_app = web_app;
}
public void check_requirements() throws Drt.RequirementError {
parser.eval(web_app.requirements);
}
}
}
} // namespace Nuvola
@@ -25,27 +25,8 @@
namespace Nuvola {
public abstract class WebOptions : GLib.Object {
private static bool have_default;
private static Type? default_options_class = null;
public static bool set_default(Type type) {
if (!have_default) {
default_options_class = type;
have_default = true;
return true;
}
return false;
}
public static Type get_default() {
return have_default ? default_options_class : null;
}
public static WebOptions? create_default(WebAppStorage storage) {
if (have_default) {
return (WebOptions) GLib.Object.@new(default_options_class, "storage", storage);
}
return null;
public static WebOptions? create(Type type, WebAppStorage storage) {
return GLib.Object.@new(type, "storage", storage) as WebOptions;
}
public WebAppStorage storage {get; construct;}

0 comments on commit f521fdf

Please sign in to comment.