Skip to content

Commit ab6bc94

Browse files
authored
Merge pull request #2791 from tadeasf/fix/linux-update-dialog-webview-crash
Fix Linux startup crash caused by the update notification dialog
2 parents ab5ddaf + ce4bc21 commit ab6bc94

3 files changed

Lines changed: 109 additions & 40 deletions

File tree

dist_assets/linux/AppImageBuilder.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ AppDir:
3030
# wx dependencies
3131
- libgtk-3-0
3232
- librsvg2-common # GTK3 recommendation; without it, search in char editor crashes
33-
- libwebkit2gtk-4.0-37 # Needed for wx's HTML lib
3433
# Unknown
3534
- libpcre2-32-0 # https://github.com/pyfa-org/Pyfa/issues/2572
3635
- libnotify4 # https://github.com/pyfa-org/Pyfa/issues/2598

gui/mainFrame.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,16 @@ def getCommandForFit(self, fitID) -> wx.CommandProcessor:
242242
return Fit.getCommandProcessor(fitID)
243243

244244
def ShowUpdateBox(self, release, version):
245-
with UpdateDialog(self, release, version) as dlg:
246-
dlg.ShowModal()
245+
# This runs right after startup, so any failure here must not be able
246+
# to take the whole application down with it
247+
try:
248+
with UpdateDialog(self, release, version) as dlg:
249+
dlg.ShowModal()
250+
except (KeyboardInterrupt, SystemExit):
251+
raise
252+
except Exception as e:
253+
pyfalog.error("Caught exception while showing the update notification dialog")
254+
pyfalog.error(e)
247255

248256
def LoadPreviousOpenFits(self):
249257
sFit = Fit.getInstance()

gui/updateDialog.py

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@
2121
import wx
2222
# noinspection PyPackageRequirements
2323
import dateutil.parser
24+
from logbook import Logger
2425
from service.settings import UpdateSettings as svc_UpdateSettings
25-
import wx.html2
2626
import webbrowser
2727
import re
2828
import markdown2
2929

30+
pyfalog = Logger(__name__)
31+
3032
_t = wx.GetTranslation
3133

3234
# HTML template. We link to a bootstrap cdn for quick and easy css, and include some additional teaks.
@@ -51,8 +53,8 @@ class UpdateDialog(wx.Dialog):
5153

5254
def __init__(self, parent, release, version):
5355
super().__init__(
54-
parent, id=wx.ID_ANY, title="pyfa {}" + _t("Update Available"), pos=wx.DefaultPosition,
55-
size=wx.Size(550, 450), style=wx.DEFAULT_DIALOG_STYLE)
56+
parent, id=wx.ID_ANY, title="pyfa {} - {}".format(release['tag_name'], _t("Update Available")),
57+
pos=wx.DefaultPosition, size=wx.Size(550, 450), style=wx.DEFAULT_DIALOG_STYLE)
5658

5759
self.UpdateSettings = svc_UpdateSettings.getInstance()
5860
self.releaseInfo = release
@@ -61,42 +63,22 @@ def __init__(self, parent, release, version):
6163
mainSizer = wx.BoxSizer(wx.VERTICAL)
6264

6365
releaseDate = dateutil.parser.parse(self.releaseInfo['published_at'])
66+
releaseNotes = self.releaseInfo.get('body') or ''
6467
notesSizer = wx.BoxSizer(wx.HORIZONTAL)
65-
self.browser = wx.html2.WebView.New(self)
66-
self.browser.Bind(wx.html2.EVT_WEBVIEW_NEWWINDOW, self.OnNewWindow)
67-
68-
link_patterns = [
69-
(re.compile(r"#(\d+)", re.I), r"https://github.com/pyfa-org/Pyfa/issues/\1"),
70-
(re.compile(r"@(\w+)", re.I), r"https://github.com/\1")
71-
]
72-
73-
markdowner = markdown2.Markdown(
74-
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
75-
link_patterns=link_patterns)
76-
77-
release_markup = markdowner.convert(self.releaseInfo['body'])
78-
79-
# run the text through markup again, this time with the hashing pattern. This is required due to bugs in markdown2:
80-
# https://github.com/trentm/python-markdown2/issues/287
81-
link_patterns = [
82-
(re.compile("([0-9a-f]{6,40})", re.I), r"https://github.com/pyfa-org/Pyfa/commit/\1"),
83-
]
8468

85-
markdowner = markdown2.Markdown(
86-
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
87-
link_patterns=link_patterns)
88-
89-
# The space here is required, again, due to bug. Again, see https://github.com/trentm/python-markdown2/issues/287
90-
release_markup = markdowner.convert(' ' + release_markup)
91-
92-
self.browser.SetPage(html_tmpl.format(
93-
self.releaseInfo['tag_name'],
94-
releaseDate.strftime('%B %d, %Y'),
95-
"<p class='text-danger'><b>This is a pre-release, be prepared for unstable features</b></p>" if version.is_prerelease else "",
96-
release_markup
97-
), "")
98-
99-
notesSizer.Add(self.browser, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 5)
69+
self.browser = self.createNotesBrowser(releaseDate, releaseNotes, version)
70+
if self.browser is None:
71+
header = "pyfa {} ({})".format(self.releaseInfo['tag_name'], releaseDate.strftime('%B %d, %Y'))
72+
lines = [header, '=' * len(header), '']
73+
if version.is_prerelease:
74+
lines += [_t("This is a pre-release, be prepared for unstable features"), '']
75+
lines.append(releaseNotes)
76+
self.notesText = wx.TextCtrl(
77+
self, wx.ID_ANY, '\n'.join(lines), wx.DefaultPosition, wx.DefaultSize,
78+
wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_WORDWRAP)
79+
notesSizer.Add(self.notesText, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 5)
80+
else:
81+
notesSizer.Add(self.browser, 1, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 5)
10082
mainSizer.Add(notesSizer, 1, wx.EXPAND, 5)
10183

10284
self.supressCheckbox = wx.CheckBox(self, wx.ID_ANY, _t("Don't remind me again for this release"),
@@ -131,6 +113,86 @@ def __init__(self, parent, release, version):
131113

132114
self.Centre(wx.BOTH)
133115

116+
@staticmethod
117+
def webViewAvailable():
118+
"""
119+
On wxGTK the wx.html2.WebView widget is backed by WebKitGTK, which cannot
120+
be instantiated reliably on every Linux setup. In particular, the AppImage
121+
bundles an Ubuntu build of WebKitGTK that fails to spawn its helper
122+
processes on other distributions, aborting the whole application
123+
(see https://github.com/pyfa-org/Pyfa/issues/2740). Never use the WebView
124+
there; on other platforms make sure a backend can be loaded at all.
125+
"""
126+
if 'wxGTK' in wx.PlatformInfo:
127+
return False
128+
try:
129+
from wx import html2
130+
return html2.WebView.IsBackendAvailable(html2.WebViewBackendDefault)
131+
except (KeyboardInterrupt, SystemExit):
132+
raise
133+
except Exception as e:
134+
pyfalog.warning("Could not check WebView backend availability: {}", e)
135+
return False
136+
137+
def createNotesBrowser(self, releaseDate, releaseNotes, version):
138+
"""
139+
Build the WebView displaying the release notes. Returns None when the
140+
WebView cannot be used, so the caller can fall back to plain text.
141+
"""
142+
if not self.webViewAvailable():
143+
return None
144+
145+
from wx import html2
146+
try:
147+
browser = html2.WebView.New(self)
148+
except (KeyboardInterrupt, SystemExit):
149+
raise
150+
except Exception as e:
151+
pyfalog.warning("Could not create WebView for the update dialog: {}", e)
152+
return None
153+
154+
browser.Bind(html2.EVT_WEBVIEW_NEWWINDOW, self.OnNewWindow)
155+
156+
link_patterns = [
157+
(re.compile(r"#(\d+)", re.I), r"https://github.com/pyfa-org/Pyfa/issues/\1"),
158+
(re.compile(r"@(\w+)", re.I), r"https://github.com/\1")
159+
]
160+
161+
markdowner = markdown2.Markdown(
162+
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
163+
link_patterns=link_patterns)
164+
165+
release_markup = markdowner.convert(releaseNotes)
166+
167+
# run the text through markup again, this time with the hashing pattern. This is required due to bugs in markdown2:
168+
# https://github.com/trentm/python-markdown2/issues/287
169+
link_patterns = [
170+
(re.compile("([0-9a-f]{6,40})", re.I), r"https://github.com/pyfa-org/Pyfa/commit/\1"),
171+
]
172+
173+
markdowner = markdown2.Markdown(
174+
extras=['cuddled-lists', 'fenced-code-blocks', 'target-blank-links', 'toc', 'link-patterns'],
175+
link_patterns=link_patterns)
176+
177+
# The space here is required, again, due to bug. Again, see https://github.com/trentm/python-markdown2/issues/287
178+
release_markup = markdowner.convert(' ' + release_markup)
179+
180+
try:
181+
browser.SetPage(html_tmpl.format(
182+
self.releaseInfo['tag_name'],
183+
releaseDate.strftime('%B %d, %Y'),
184+
"<p class='text-danger'><b>This is a pre-release, be prepared for unstable features</b></p>" if version.is_prerelease else "",
185+
release_markup
186+
), "")
187+
except (KeyboardInterrupt, SystemExit):
188+
raise
189+
except Exception as e:
190+
pyfalog.warning("Could not load release notes into WebView: {}", e)
191+
browser.Destroy()
192+
return None
193+
194+
return browser
195+
134196
def OnClose(self, e):
135197
self.Close()
136198

0 commit comments

Comments
 (0)