Blog

Qt WebEngine window.close() error

One of my current projects is a Qt project that uses an embedded QWebEngineView to handle some of the UI logic. A part of the code base relies on a combination of the QWebEnginePage::windowCloseRequested() signal and the window.close() javascript function to capture certain close events. Strangely, there was a defect whereby calling window.close() would generally work but in certain circumstances it would stop working all together. The javascript console would then output a standard warning that looked like this:

Scripts may close only the windows that were opened by it.

While this is a standard security protocol in the browser, it was perplexing to see it here as the security setting to allow scripts to close pages was allowed. Furthermore, this particular page was not created by a script as it was the index page of a single-page-application.

After having no luck figuring out the issue I became curious to understand what was happening in the QWebEngineView that was triggering this warning. Since the Qt Web Engine is based on chromium, I grepped the source and found this:

Settings* settings = frame()->settings();
bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows();
if (!page->openedByDOM() && frame()->client()->backForwardLength() > 1 && !allowScriptsToCloseWindows) {
    if (activeDocument) {
        activeDocument->domWindow()->frameConsole()->addMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, "Scripts may close only the windows that were opened by it."));
    }
    return;
}

By process of elimination, I discovered that the offending check had to be frame()->client()->backForwardLength. After some experimenting I learned that the window.close() error only occurred after I clicked on an anchor tag which created a navigation event (i.e. increased backForwardLength() by 1). Supressing the default event prevented this issue.

CONCLUSION: When relying on the window.close() event in chromium based projects, ensure that the web client doesn't create a navigation event. Either avoid using anchor tags, forms, etc. or supress the default behavior in javascript using something like preventDefault().