From 2f2b3cf638f3659293fdba230c04d91fcd8cf597 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 6 Sep 2019 12:13:30 +0530 Subject: [PATCH] Fix crashes when using webengine on windows with no native GUI Tell Qt to use the software OpenGL renderer in headless mode on windows. --- src/calibre/gui2/__init__.py | 8 ++++++ src/calibre/test_build.py | 47 +++++++++++++++++------------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index ff83ed0242..b671478b9a 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1203,6 +1203,8 @@ def ensure_app(headless=True): args += ['-platformpluginpath', plugins_loc, '-platform', 'headless'] if isosx: os.environ['QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM'] = '1' + if headless and iswindows: + QApplication.setAttribute(Qt.AA_UseSoftwareOpenGL, True) _store_app = QApplication(args) if headless and has_headless: _store_app.headless = True @@ -1222,6 +1224,12 @@ def ensure_app(headless=True): except: pass sys.excepthook = eh + return _store_app + + +def destroy_app(): + global _store_app + _store_app = None def app_is_headless(): diff --git a/src/calibre/test_build.py b/src/calibre/test_build.py index a0e49c11ff..f5faae5535 100644 --- a/src/calibre/test_build.py +++ b/src/calibre/test_build.py @@ -187,6 +187,7 @@ class BuildTest(unittest.TestCase): @unittest.skipIf('SKIP_QT_BUILD_TEST' in os.environ, 'Skipping Qt build test as it causes crashes in the macOS VM') def test_qt(self): from PyQt5.QtCore import QTimer + from PyQt5.QtWidgets import QApplication from PyQt5.QtWebEngineWidgets import QWebEnginePage from PyQt5.QtGui import QImageReader, QFontDatabase from PyQt5.QtNetwork import QNetworkAccessManager @@ -210,42 +211,38 @@ class BuildTest(unittest.TestCase): # Run the imaging tests test() - from calibre.gui2 import Application + from calibre.gui2 import ensure_app, destroy_app os.environ.pop('DISPLAY', None) - has_headless = isosx or islinux - app = Application([], headless=has_headless) + ensure_app() self.assertGreaterEqual(len(QFontDatabase().families()), 5, 'The QPA headless plugin is not able to locate enough system fonts via fontconfig') - if has_headless: - from calibre.ebooks.covers import create_cover - create_cover('xxx', ['yyy']) + from calibre.ebooks.covers import create_cover + create_cover('xxx', ['yyy']) na = QNetworkAccessManager() self.assertTrue(hasattr(na, 'sslErrors'), 'Qt not compiled with openssl') if iswindows: from PyQt5.Qt import QtWin QtWin - if has_headless: - # Causes crash on exit under windows+cygwin+ssh - p = QWebEnginePage() + p = QWebEnginePage() - def callback(result): - callback.result = result - if hasattr(print_callback, 'result'): - Application.instance().quit() + def callback(result): + callback.result = result + if hasattr(print_callback, 'result'): + QApplication.instance().quit() - def print_callback(result): - print_callback.result = result - if hasattr(callback, 'result'): - Application.instance().quit() + def print_callback(result): + print_callback.result = result + if hasattr(callback, 'result'): + QApplication.instance().quit() - p.runJavaScript('1 + 1', callback) - p.printToPdf(print_callback) - QTimer.singleShot(5000, lambda: Application.instance().quit()) - app.exec_() - self.assertEqual(callback.result, 2) - self.assertIn(b'Skia/PDF', bytes(print_callback.result)) - del p + p.runJavaScript('1 + 1', callback) + p.printToPdf(print_callback) + QTimer.singleShot(5000, lambda: QApplication.instance().quit()) + QApplication.instance().exec_() + self.assertEqual(callback.result, 2) + self.assertIn(b'Skia/PDF', bytes(print_callback.result)) + del p del na - del app + destroy_app() del QWebEnginePage def test_imaging(self):