Fix crashes when using webengine on windows with no native GUI

Tell Qt to use the software OpenGL renderer in headless mode on windows.
This commit is contained in:
Kovid Goyal 2019-09-06 12:13:30 +05:30
parent 03929d5959
commit 2f2b3cf638
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 30 additions and 25 deletions

View File

@ -1203,6 +1203,8 @@ def ensure_app(headless=True):
args += ['-platformpluginpath', plugins_loc, '-platform', 'headless'] args += ['-platformpluginpath', plugins_loc, '-platform', 'headless']
if isosx: if isosx:
os.environ['QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM'] = '1' os.environ['QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM'] = '1'
if headless and iswindows:
QApplication.setAttribute(Qt.AA_UseSoftwareOpenGL, True)
_store_app = QApplication(args) _store_app = QApplication(args)
if headless and has_headless: if headless and has_headless:
_store_app.headless = True _store_app.headless = True
@ -1222,6 +1224,12 @@ def ensure_app(headless=True):
except: except:
pass pass
sys.excepthook = eh sys.excepthook = eh
return _store_app
def destroy_app():
global _store_app
_store_app = None
def app_is_headless(): def app_is_headless():

View File

@ -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') @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): def test_qt(self):
from PyQt5.QtCore import QTimer from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEnginePage from PyQt5.QtWebEngineWidgets import QWebEnginePage
from PyQt5.QtGui import QImageReader, QFontDatabase from PyQt5.QtGui import QImageReader, QFontDatabase
from PyQt5.QtNetwork import QNetworkAccessManager from PyQt5.QtNetwork import QNetworkAccessManager
@ -210,42 +211,38 @@ class BuildTest(unittest.TestCase):
# Run the imaging tests # Run the imaging tests
test() test()
from calibre.gui2 import Application from calibre.gui2 import ensure_app, destroy_app
os.environ.pop('DISPLAY', None) os.environ.pop('DISPLAY', None)
has_headless = isosx or islinux ensure_app()
app = Application([], headless=has_headless)
self.assertGreaterEqual(len(QFontDatabase().families()), 5, 'The QPA headless plugin is not able to locate enough system fonts via fontconfig') 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
from calibre.ebooks.covers import create_cover create_cover('xxx', ['yyy'])
create_cover('xxx', ['yyy'])
na = QNetworkAccessManager() na = QNetworkAccessManager()
self.assertTrue(hasattr(na, 'sslErrors'), 'Qt not compiled with openssl') self.assertTrue(hasattr(na, 'sslErrors'), 'Qt not compiled with openssl')
if iswindows: if iswindows:
from PyQt5.Qt import QtWin from PyQt5.Qt import QtWin
QtWin QtWin
if has_headless: p = QWebEnginePage()
# Causes crash on exit under windows+cygwin+ssh
p = QWebEnginePage()
def callback(result): def callback(result):
callback.result = result callback.result = result
if hasattr(print_callback, 'result'): if hasattr(print_callback, 'result'):
Application.instance().quit() QApplication.instance().quit()
def print_callback(result): def print_callback(result):
print_callback.result = result print_callback.result = result
if hasattr(callback, 'result'): if hasattr(callback, 'result'):
Application.instance().quit() QApplication.instance().quit()
p.runJavaScript('1 + 1', callback) p.runJavaScript('1 + 1', callback)
p.printToPdf(print_callback) p.printToPdf(print_callback)
QTimer.singleShot(5000, lambda: Application.instance().quit()) QTimer.singleShot(5000, lambda: QApplication.instance().quit())
app.exec_() QApplication.instance().exec_()
self.assertEqual(callback.result, 2) self.assertEqual(callback.result, 2)
self.assertIn(b'Skia/PDF', bytes(print_callback.result)) self.assertIn(b'Skia/PDF', bytes(print_callback.result))
del p del p
del na del na
del app destroy_app()
del QWebEnginePage del QWebEnginePage
def test_imaging(self): def test_imaging(self):