diff --git a/openlp/core/display/html/display.js b/openlp/core/display/html/display.js
index 576b6b0d2..78e1384c9 100644
--- a/openlp/core/display/html/display.js
+++ b/openlp/core/display/html/display.js
@@ -262,6 +262,7 @@ var Display = {
_animationState: AnimationState.NoAnimation,
_doTransitions: false,
_doItemTransitions: false,
+ _skipNextTransition: false,
_themeApplied: true,
_revealConfig: {
margin: 0.0,
@@ -365,7 +366,7 @@ var Display = {
Display.applyTheme(new_slides, is_text);
Display._slidesContainer.prepend(new_slides);
var currentSlide = Reveal.getIndices();
- if (Display._doItemTransitions && Display._slidesContainer.children.length >= 2) {
+ if (Display._doItemTransitions && Display._slidesContainer.children.length >= 2 && !Display._skipNextTransition) {
// Set the slide one section ahead so we'll stay on the old slide after reinit
Reveal.slide(1, currentSlide.v);
Display.reinit();
@@ -375,6 +376,7 @@ var Display = {
Reveal.slide(0, currentSlide.v);
Reveal.sync();
Display._removeLastSection();
+ Display._skipNextTransition = false;
}
},
/**
@@ -1121,6 +1123,18 @@ var Display = {
}
}
},
+ /**
+ * Called whenever openlp wants to finish completely with the current text/image slides
+ * because a different window (eg presentation or vlc) is going to be displaying the next item
+ * and we don't want any flashbacks to the current slide contents
+ */
+ finishWithCurrentItem: function () {
+ Display.setTextSlide('');
+ var documentBody = $("body")[0];
+ documentBody.style.opacity = 1;
+ Display._skipNextTransition = true;
+ displayWatcher.pleaseRepaint();
+ },
/**
* Return the video types supported by the video tag
*/
diff --git a/openlp/core/display/window.py b/openlp/core/display/window.py
index 7ab7ed62b..4fb471eee 100644
--- a/openlp/core/display/window.py
+++ b/openlp/core/display/window.py
@@ -51,6 +51,10 @@ class DisplayWatcher(QtCore.QObject):
"""
initialised = QtCore.pyqtSignal(bool)
+ def __init__(self, parent):
+ super().__init__()
+ self._display_window = parent
+
@QtCore.pyqtSlot(bool)
def setInitialised(self, is_initialised):
"""
@@ -59,6 +63,13 @@ class DisplayWatcher(QtCore.QObject):
log.info('Display is initialised: {init}'.format(init=is_initialised))
self.initialised.emit(is_initialised)
+ @QtCore.pyqtSlot()
+ def pleaseRepaint(self):
+ """
+ Called from the js in the webengine view when it's requesting a repaint by Qt
+ """
+ self._display_window.webview.update()
+
class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
"""
@@ -451,6 +462,16 @@ class DisplayWindow(QtWidgets.QWidget, RegistryProperties, LogMixin):
if self.is_display and self.hide_mode == HideMode.Screen:
self.setVisible(False)
+ def finish_with_current_item(self):
+ """
+ This is called whenever the song/image display is followed by eg a presentation or video which
+ has its own display.
+ This function ensures that the current item won't flash momentarily when the webengineview
+ is displayed for a subsequent song or image.
+ """
+ self.run_javascript('Display.finishWithCurrentItem();', True)
+ self.webview.update()
+
def set_scale(self, scale):
"""
Set the HTML scale
diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py
index e0358b301..03ba23208 100644
--- a/openlp/core/ui/slidecontroller.py
+++ b/openlp/core/ui/slidecontroller.py
@@ -945,23 +945,19 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
[self.service_item, self.is_live, self._current_hide_mode, slide_no])
else:
self._set_theme(self.service_item)
- # Reset blanking if needed
- if old_item and self.is_live and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or
- self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)):
- self._reset_blank(self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay))
self.info_label.setText(self.service_item.title)
self.slide_list = {}
- if old_item:
- # Close the old item if it's not to be used by the new service item
- if not self.service_item.is_media() and not self.service_item.requires_media():
- self.on_media_close()
- if old_item.is_command() and not old_item.is_media():
- Registry().execute('{name}_stop'.format(name=old_item.name.lower()), [old_item, self.is_live])
- # if the old item was media which hid the main display then need to reset it if new service item uses it
- if self.is_live and self._current_hide_mode is None and old_item.is_media() and not \
- old_item.requires_media() and not self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
- for display in self.displays:
- display.show_display()
+ # if the old item was text or images (ie doesn't provide its own display) and the new item provides its own
+ # display then clear out the old item so that it doesn't flash momentarily when next showing text/image
+ # An item provides its own display if the capability ProvidesOwnDisplay is set or if it's a media item
+ old_item_provides_own_display = old_item and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or
+ old_item.is_media())
+ new_item_provides_own_display = (self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or
+ self.service_item.is_media())
+ if self.is_live and not old_item_provides_own_display and new_item_provides_own_display:
+ for display in self.displays:
+ display.finish_with_current_item()
+ # Prepare the new slides for text / image items
row = 0
width = self.main_window.control_splitter.sizes()[self.split]
if self.service_item.is_text():
@@ -997,7 +993,23 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
row += 1
self.slide_list[str(row)] = row - 1
self.preview_widget.replace_service_item(self.service_item, width, slide_no)
+ # Tidy up aspects associated with the old item
+ if old_item:
+ # Close the old item if it's not to be used by the new service item
+ if not self.service_item.is_media() and not self.service_item.requires_media():
+ self.on_media_close()
+ if old_item.is_command() and not old_item.is_media():
+ Registry().execute('{name}_stop'.format(name=old_item.name.lower()), [old_item, self.is_live])
+ # if the old item was media which hid the main display then need to reset it if new service item uses it
+ if self.is_live and self._current_hide_mode is None and old_item.is_media() and not \
+ old_item.requires_media() and not self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
+ for display in self.displays:
+ display.show_display()
self.enable_tool_bar(self.service_item)
+ # Reset blanking if needed
+ if old_item and self.is_live and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or
+ self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)):
+ self._reset_blank(self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay))
if self.service_item.is_media() or self.service_item.requires_media():
self._set_theme(self.service_item)
if self.service_item.is_command():
diff --git a/tests/openlp_core/display/test_window.py b/tests/openlp_core/display/test_window.py
index 5f1f224b3..2b43f0f8e 100644
--- a/tests/openlp_core/display/test_window.py
+++ b/tests/openlp_core/display/test_window.py
@@ -622,3 +622,18 @@ def test_display_watcher_set_initialised():
# THEN: initialised should have been emitted
mocked_initialised.emit.assert_called_once_with(True)
+
+
+def test_display_watcher_please_repaint(display_window_env, mock_settings):
+ """
+ Test that the repaint is initiated
+ """
+ # GIVEN: A DisplayWindow instance with mocked out webview
+ display_window = DisplayWindow()
+ display_window.webview = MagicMock()
+
+ # WHEN: pleaseRepaint is called on the DisplayWatcher
+ display_window.display_watcher.pleaseRepaint()
+
+ # THEN: Qt update for the webview should have been triggered
+ assert display_window.webview.update.call_count == 1