Skip to content

Commit b138f49

Browse files
authored
Merge pull request #3684 from OpenShot/backend-checking
Alternate backend-loading approach for Timeline
2 parents d7db9f0 + 3688bab commit b138f49

File tree

12 files changed

+446
-369
lines changed

12 files changed

+446
-369
lines changed

src/classes/app.py

+32-17
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,28 @@
3535

3636
from PyQt5.QtCore import PYQT_VERSION_STR
3737
from PyQt5.QtCore import QT_VERSION_STR
38-
from PyQt5.QtCore import Qt
38+
from PyQt5.QtCore import Qt, pyqtSlot
3939
from PyQt5.QtGui import QPalette, QColor, QFontDatabase, QFont
4040
from PyQt5.QtWidgets import QApplication, QStyleFactory, QMessageBox
4141

4242
try:
43-
# QtWebEngineWidgets must be loaded prior to creating a QApplication
44-
# But on systems with only WebKit, this will fail (and we ignore the failure)
45-
from PyQt5.QtWebEngineWidgets import QWebEngineView
46-
except ImportError:
43+
# This apparently has to be done before loading QtQuick
44+
# (via QtWebEgine) AND before creating the QApplication instance
45+
QApplication.setAttribute(Qt.AA_ShareOpenGLContexts)
46+
from OpenGL import GL # noqa
47+
except (ImportError, AttributeError):
4748
pass
4849

4950
try:
50-
# Solution to solve QtWebEngineWidgets black screen caused by OpenGL not loaded
51-
from OpenGL import GL
51+
# QtWebEngineWidgets must be loaded prior to creating a QApplication
52+
# But on systems with only WebKit, this will fail (and we ignore the failure)
53+
from PyQt5.QtWebEngineWidgets import QWebEngineView
5254
except ImportError:
5355
pass
5456

5557
try:
5658
# Enable High-DPI resolutions
5759
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
58-
QApplication.setAttribute(Qt.AA_ShareOpenGLContexts)
5960
except AttributeError:
6061
pass # Quietly fail for older Qt5 versions
6162

@@ -83,8 +84,10 @@ def __init__(self, *args, mode=None):
8384
log.info(time.asctime().center(48))
8485
log.info('Starting new session'.center(48))
8586

86-
from classes import settings, project_data, updates, language, ui_util, logger_libopenshot
87-
from . import openshot_rc # noqa
87+
from classes import (
88+
settings, project_data, updates, language, ui_util,
89+
logger_libopenshot
90+
)
8891
import openshot
8992

9093
# Re-route stdout and stderr to logger
@@ -127,7 +130,7 @@ def __init__(self, *args, mode=None):
127130
pass
128131

129132
# Init settings
130-
self.settings = settings.SettingStore()
133+
self.settings = settings.SettingStore(parent=self)
131134
self.settings.load()
132135

133136
# Init and attach exception handler
@@ -247,12 +250,15 @@ def __init__(self, *args, mode=None):
247250

248251
# Create main window
249252
from windows.main_window import MainWindow
250-
self.window = MainWindow(mode)
253+
self.window = MainWindow(mode=mode)
251254

252255
# Reset undo/redo history
253256
self.updates.reset()
254257
self.window.updateStatusChanged(False, False)
255258

259+
# Connect our exit signals
260+
self.aboutToQuit.connect(self.cleanup)
261+
256262
log.info('Process command-line arguments: %s' % args)
257263
if len(args[0]) == 2:
258264
path = args[0][1]
@@ -267,24 +273,33 @@ def __init__(self, *args, mode=None):
267273
# Recover backup file (this can't happen until after the Main Window has completely loaded)
268274
self.window.RecoverBackup.emit()
269275

276+
def settings_load_error(self, filepath=None):
277+
"""Use QMessageBox to warn the user of a settings load issue"""
278+
_ = self._tr
279+
QMessageBox.warning(
280+
None,
281+
_("Settings Error"),
282+
_("Error loading settings file: %(file_path)s. Settings will be reset.")
283+
% {"file_path": filepath}
284+
)
285+
270286
def _tr(self, message):
271287
return self.translate("", message)
272288

273289
# Start event loop
274290
def run(self):
275291
""" Start the primary Qt event loop for the interface """
292+
return self.exec_()
276293

277-
res = self.exec_()
278-
294+
@pyqtSlot()
295+
def cleanup(self):
296+
"""aboutToQuit signal handler for application exit"""
279297
try:
280298
from classes.logger import log
281299
self.settings.save()
282300
except Exception:
283301
log.error("Couldn't save user settings on exit.", exc_info=1)
284302

285-
# return exit result
286-
return res
287-
288303

289304
# Log the session's end
290305
@atexit.register

src/classes/exceptions.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
"""
1+
"""
22
@file
33
@brief This file deals with unhandled exceptions
44
@author Jonathan Thomas <[email protected]>
5-
5+
66
@section LICENSE
7-
7+
88
Copyright (c) 2008-2018 OpenShot Studios, LLC
99
(http://www.openshotstudios.com). This file is part of
1010
OpenShot Video Editor (http://www.openshot.org), an open-source project
1111
dedicated to delivering high quality video editing and animation solutions
1212
to the world.
13-
13+
1414
OpenShot Video Editor is free software: you can redistribute it and/or modify
1515
it under the terms of the GNU General Public License as published by
1616
the Free Software Foundation, either version 3 of the License, or
1717
(at your option) any later version.
18-
18+
1919
OpenShot Video Editor is distributed in the hope that it will be useful,
2020
but WITHOUT ANY WARRANTY; without even the implied warranty of
2121
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2222
GNU General Public License for more details.
23-
23+
2424
You should have received a copy of the GNU General Public License
2525
along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
2626
"""

src/classes/info.py

+3
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@
9292
LOG_LEVEL_FILE = 'INFO'
9393
LOG_LEVEL_CONSOLE = 'INFO'
9494

95+
# Web backend selection, overridable at launch
96+
WEB_BACKEND = 'auto'
97+
9598
# Languages
9699
CMDLINE_LANGUAGE = None
97100
CURRENT_LANGUAGE = 'en_US'

src/classes/settings.py

+35-23
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,64 @@
1-
"""
1+
"""
22
@file
3-
@brief This file loads and saves settings
3+
@brief This file loads and saves settings
44
@author Noah Figg <[email protected]>
55
@author Jonathan Thomas <[email protected]>
66
@author Olivier Girard <[email protected]>
7-
7+
88
@section LICENSE
9-
9+
1010
Copyright (c) 2008-2018 OpenShot Studios, LLC
1111
(http://www.openshotstudios.com). This file is part of
1212
OpenShot Video Editor (http://www.openshot.org), an open-source project
1313
dedicated to delivering high quality video editing and animation solutions
1414
to the world.
15-
15+
1616
OpenShot Video Editor is free software: you can redistribute it and/or modify
1717
it under the terms of the GNU General Public License as published by
1818
the Free Software Foundation, either version 3 of the License, or
1919
(at your option) any later version.
20-
20+
2121
OpenShot Video Editor is distributed in the hope that it will be useful,
2222
but WITHOUT ANY WARRANTY; without even the implied warranty of
2323
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2424
GNU General Public License for more details.
25-
25+
2626
You should have received a copy of the GNU General Public License
2727
along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
2828
"""
2929

3030
# SettingStore - class which allows getting/storing of settings, loading and saving to json
3131
import os
3232

33-
from PyQt5.QtCore import QStandardPaths, QCoreApplication
34-
from PyQt5.QtWidgets import QMessageBox
35-
36-
from classes.logger import log
3733
from classes import info
34+
from classes.logger import log
3835
from classes.json_data import JsonDataStore
3936

4037

4138
def get_settings():
42-
""" Get the current QApplication's settings instance """
43-
return QCoreApplication.instance().settings
39+
""" Get the current application's settings instance """
40+
return SettingStore.get_app().settings
4441

4542

4643
class SettingStore(JsonDataStore):
4744
""" This class only allows setting pre-existing keys taken from default settings file, and merges user settings
4845
on load, assumes default OS dir."""
4946

50-
def __init__(self):
51-
JsonDataStore.__init__(self)
47+
@classmethod
48+
def save_app(cls, app_reference):
49+
cls._app = app_reference
50+
51+
@classmethod
52+
def get_app(cls):
53+
if hasattr(cls, "_app"):
54+
return cls._app
55+
return None
56+
57+
def __init__(self, parent=None):
58+
super().__init__()
59+
# Also keep track of our parent, if defined
60+
if parent:
61+
SettingStore.save_app(parent)
5262
# Set the data type name for logging clarity (base class functions use this variable)
5363
self.data_type = "user settings"
5464
self.settings_filename = "openshot.settings"
@@ -72,8 +82,11 @@ def set(self, key, value):
7282
if key in user_values:
7383
user_values[key]["value"] = value
7484
else:
75-
log.warn("{} key '{}' not valid. The following are valid: {}".format(self.data_type, key,
76-
list(self._data.keys())))
85+
log.warn(
86+
"{} key '{}' not valid. The following are valid: {}".format(
87+
self.data_type, key,
88+
list(self._data.keys()),
89+
))
7790

7891
def load(self):
7992
""" Load user settings file from disk, merging with allowed settings in default settings file.
@@ -90,17 +103,16 @@ def load(self):
90103

91104
# Load user settings (if found)
92105
if os.path.exists(os.fsencode(file_path)):
93-
94106
# Will raise exception to caller on failure to read
95107
try:
96108
user_settings = self.read_from_file(file_path)
97109
except Exception as ex:
98-
log.error("Error loading settings file: %s" % ex)
99-
100-
_ = QCoreApplication.instance()._tr
101-
QMessageBox.warning(None, _("Settings Error"),
102-
_("Error loading settings file: %(file_path)s. Settings will be reset.") % { "file_path": file_path})
110+
log.error("Error loading settings file: %s", ex)
103111
user_settings = {}
112+
app = SettingStore.get_app()
113+
if app:
114+
# We have a parent, ask to show a message box
115+
app.settings_load_error(file_path)
104116

105117
# Merge default and user settings, excluding settings not in default, Save settings
106118
self._data = self.merge_settings(default_settings, user_settings)

src/classes/thumbnail.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ def run(self):
107107
self.server_address = ('127.0.0.1', self.find_free_port())
108108
self.thumbServer = httpThumbnailServer(self.server_address, httpThumbnailHandler)
109109
self.thumbServer.daemon_threads = True
110+
log.info(
111+
"Starting thumbnail server listening on port %d",
112+
self.server_address[1])
110113
self.thumbServer.serve_forever(0.5)
111114

112115
def __init__(self):
@@ -128,6 +131,8 @@ def log_error(self, msg_format, *args):
128131

129132
def do_GET(self):
130133
""" Process each GET request and return a value (image or file path)"""
134+
mask_path = os.path.join(info.IMAGES_PATH, "mask.png")
135+
131136
# Parse URL
132137
url_output = REGEX_THUMBNAIL_URL.match(self.path)
133138
if url_output and len(url_output.groups()) == 4:
@@ -147,6 +152,10 @@ def do_GET(self):
147152
only_path = url_output.group('only_path')
148153
no_cache = url_output.group('no_cache')
149154

155+
log.debug(
156+
"Processing thumbnail request for %s frame %d",
157+
file_id, file_frame)
158+
150159
try:
151160
# Look up file data
152161
file = File.get(id=file_id)
@@ -155,6 +164,7 @@ def do_GET(self):
155164
file_path = file.absolute_path()
156165
except AttributeError:
157166
# Couldn't match file ID
167+
log.debug("No ID match, returning 404")
158168
self.send_error(404)
159169
return
160170

@@ -183,7 +193,13 @@ def do_GET(self):
183193
overlay_path = os.path.join(info.IMAGES_PATH, "overlay.png")
184194

185195
# Create thumbnail image
186-
GenerateThumbnail(file_path, thumb_path, file_frame, 98, 64, os.path.join(info.IMAGES_PATH, "mask.png"), overlay_path)
196+
GenerateThumbnail(
197+
file_path,
198+
thumb_path,
199+
file_frame,
200+
98, 64,
201+
mask_path,
202+
overlay_path)
187203

188204
# Send message back to client
189205
if os.path.exists(thumb_path):

src/classes/timeline.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
"""
1+
"""
22
@file
33
@brief This file contains a timeline object, which listens for updates and syncs a libopenshot timeline object
44
@author Jonathan Thomas <[email protected]>
5-
5+
66
@section LICENSE
7-
7+
88
Copyright (c) 2008-2018 OpenShot Studios, LLC
99
(http://www.openshotstudios.com). This file is part of
1010
OpenShot Video Editor (http://www.openshot.org), an open-source project
1111
dedicated to delivering high quality video editing and animation solutions
1212
to the world.
13-
13+
1414
OpenShot Video Editor is free software: you can redistribute it and/or modify
1515
it under the terms of the GNU General Public License as published by
1616
the Free Software Foundation, either version 3 of the License, or
1717
(at your option) any later version.
18-
18+
1919
OpenShot Video Editor is distributed in the hope that it will be useful,
2020
but WITHOUT ANY WARRANTY; without even the implied warranty of
2121
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2222
GNU General Public License for more details.
23-
23+
2424
You should have received a copy of the GNU General Public License
2525
along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
2626
"""

src/launch.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,12 @@ def main():
6666
help='Additional locations to search for modules '
6767
'(PYTHONPATH). Can be used multiple times.')
6868
parser.add_argument('--test-models', dest='modeltest',
69-
action='store_true',
70-
help="Load Qt's QAbstractItemModelTester into data models "
71-
'(requires Qt 5.11+)')
69+
action='store_true',
70+
help="Load Qt's QAbstractItemModelTester into data models "
71+
'(requires Qt 5.11+)')
72+
parser.add_argument('-b', '--web-backend', action='store',
73+
choices=['auto', 'webkit', 'webengine'], default='auto',
74+
help="Web backend to use for Timeline")
7275
parser.add_argument('-d', '--debug', action='store_true',
7376
help='Enable debugging output')
7477
parser.add_argument('--debug-file', action='store_true',
@@ -116,7 +119,8 @@ def main():
116119
# Set default logging rules, if the user didn't
117120
if os.getenv('QT_LOGGING_RULES') is None:
118121
os.putenv('QT_LOGGING_RULES', 'qt.modeltest.debug=true')
119-
122+
if args.web_backend:
123+
info.WEB_BACKEND = args.web_backend.lower()
120124
if args.lang:
121125
if args.lang in info.SUPPORTED_LANGUAGES:
122126
info.CMDLINE_LANGUAGE = args.lang

0 commit comments

Comments
 (0)