forked from openlp/openlp
Remove and add screens without reloading screens. Do not show screen-change-popup when the settings form is visible.
This commit is contained in:
parent
eac44f4f24
commit
73221cef9b
@ -83,7 +83,7 @@ class OpenLP(QtCore.QObject, LogMixin):
|
||||
self.server.close_server()
|
||||
return result
|
||||
|
||||
def run(self, args):
|
||||
def run(self, args, app):
|
||||
"""
|
||||
Run the OpenLP application.
|
||||
|
||||
@ -97,7 +97,7 @@ class OpenLP(QtCore.QObject, LogMixin):
|
||||
args.remove('OpenLP')
|
||||
self.args.extend(args)
|
||||
# Decide how many screens we have and their size
|
||||
screens = ScreenList.create(QtWidgets.QApplication.desktop())
|
||||
screens = ScreenList.create(app)
|
||||
# First time checks in settings
|
||||
has_run_wizard = self.settings.value('core/has run wizard')
|
||||
if not has_run_wizard:
|
||||
@ -435,4 +435,4 @@ def main():
|
||||
log.debug('Could not find translators.')
|
||||
if args and not args.no_error_form:
|
||||
sys.excepthook = app.hook_exception
|
||||
sys.exit(app.run(qt_args))
|
||||
sys.exit(app.run(qt_args, application))
|
||||
|
@ -23,6 +23,7 @@ The :mod:`screen` module provides management functionality for a machines'
|
||||
displays.
|
||||
"""
|
||||
import logging
|
||||
import copy
|
||||
from functools import cmp_to_key
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
@ -77,7 +78,14 @@ class Screen(object):
|
||||
"""
|
||||
Returns the geometry to use when displaying. This property decides between the native and custom geometries
|
||||
"""
|
||||
return self.custom_geometry or self.geometry
|
||||
# If custom geometry is used, convert to absolute position
|
||||
if self.custom_geometry:
|
||||
adjusted_custom_geometry = copy.deepcopy(self.custom_geometry)
|
||||
adjusted_custom_geometry.moveTo(self.geometry.x() + adjusted_custom_geometry.x(),
|
||||
self.geometry.y() + adjusted_custom_geometry.y())
|
||||
return adjusted_custom_geometry
|
||||
else:
|
||||
return self.geometry
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, screen_dict):
|
||||
@ -147,6 +155,13 @@ class Screen(object):
|
||||
screen_dict['custom_geometry']['width'],
|
||||
screen_dict['custom_geometry']['height'])
|
||||
|
||||
def on_geometry_changed(self, geometry):
|
||||
"""
|
||||
Callback function for when the screens geometry changes
|
||||
"""
|
||||
self.geometry = geometry
|
||||
Registry().execute('config_screen_changed')
|
||||
|
||||
|
||||
class ScreenList(metaclass=Singleton):
|
||||
"""
|
||||
@ -202,37 +217,66 @@ class ScreenList(metaclass=Singleton):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def create(cls, desktop):
|
||||
def create(cls, application):
|
||||
"""
|
||||
Initialise the screen list.
|
||||
|
||||
:param desktop: A QDesktopWidget object.
|
||||
:param desktop: A QApplication object.
|
||||
"""
|
||||
screen_list = cls()
|
||||
screen_list.desktop = desktop
|
||||
screen_list.desktop.resized.connect(screen_list.on_screen_resolution_changed)
|
||||
screen_list.desktop.screenCountChanged.connect(screen_list.on_screen_count_changed)
|
||||
screen_list.desktop.primaryScreenChanged.connect(screen_list.on_primary_screen_changed)
|
||||
screen_list.application = application
|
||||
screen_list.application.primaryScreenChanged.connect(screen_list.on_primary_screen_changed)
|
||||
screen_list.application.screenAdded.connect(screen_list.on_screen_added)
|
||||
screen_list.application.screenRemoved.connect(screen_list.on_screen_removed)
|
||||
screen_list.update_screens()
|
||||
cls.settings = Registry().get('settings')
|
||||
screen_list.load_screen_settings()
|
||||
return screen_list
|
||||
|
||||
def find_new_display_screen(self):
|
||||
"""
|
||||
If more than 1 screen, set first non-primary screen to display, otherwise just set the available screen as
|
||||
display.
|
||||
"""
|
||||
if len(self) > 1:
|
||||
for screen in self:
|
||||
if not screen.is_primary:
|
||||
screen.is_display = True
|
||||
break
|
||||
else:
|
||||
self[0].is_display = True
|
||||
|
||||
def load_screen_settings(self):
|
||||
"""
|
||||
Loads the screen size and the screen number from the settings.
|
||||
"""
|
||||
screen_settings = self.settings.value('core/screens')
|
||||
if screen_settings:
|
||||
need_new_display_screen = False
|
||||
for number, screen_dict in screen_settings.items():
|
||||
# Sometimes this loads as a string instead of an int
|
||||
number = int(number)
|
||||
if self.has_screen(number):
|
||||
# Compare geometry, primarity of screen from settings with avilable screens
|
||||
if self.has_screen(screen_dict):
|
||||
# If match was found, we're all happy, update with custom geometry, display info, if available
|
||||
self[number].update(screen_dict)
|
||||
else:
|
||||
self.screens.append(Screen.from_dict(screen_dict))
|
||||
# If no match, ignore this screen, also need to find new display screen if the discarded screen was
|
||||
# marked as such.
|
||||
if screen_dict['is_display']:
|
||||
need_new_display_screen = True
|
||||
if need_new_display_screen:
|
||||
QtWidgets.QMessageBox.warning(None, translate('OpenLP.Screen',
|
||||
'Screen settings and screen setup is not the same'),
|
||||
translate('OpenLP.Screen',
|
||||
'There is a mismatch between screens and screen settings. '
|
||||
'OpenLP will try to automatically select a display screen, but '
|
||||
'you should consider updating the screen settings.'),
|
||||
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
|
||||
self.find_new_display_screen()
|
||||
else:
|
||||
self[len(self) - 1].is_display = True
|
||||
# if no settings we need to set a display
|
||||
self.find_new_display_screen()
|
||||
|
||||
def save_screen_settings(self):
|
||||
"""
|
||||
@ -285,14 +329,15 @@ class ScreenList(metaclass=Singleton):
|
||||
if can_save:
|
||||
self.save_screen_settings()
|
||||
|
||||
def has_screen(self, number):
|
||||
def has_screen(self, screen_dict):
|
||||
"""
|
||||
Confirms a screen is known.
|
||||
|
||||
:param number: The screen number (int).
|
||||
:param screen_dict: The dict descrebing the screen.
|
||||
"""
|
||||
for screen in self.screens:
|
||||
if screen.number == number:
|
||||
if screen.to_dict()['geometry'] == screen_dict['geometry'] \
|
||||
and screen.is_primary == screen_dict['is_primary']:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -316,39 +361,44 @@ class ScreenList(metaclass=Singleton):
|
||||
else:
|
||||
return 0
|
||||
self.screens = []
|
||||
os_screens = QtWidgets.QApplication.screens()
|
||||
os_screens = self.application.screens()
|
||||
os_screens.sort(key=cmp_to_key(_screen_compare))
|
||||
for number, screen in enumerate(os_screens):
|
||||
self.screens.append(
|
||||
Screen(number, screen.geometry(), is_primary=self.desktop.primaryScreen() == number))
|
||||
Screen(number, screen.geometry(), is_primary=self.application.primaryScreen() == screen))
|
||||
screen.geometryChanged.connect(self.screens[-1].on_geometry_changed)
|
||||
|
||||
def on_screen_resolution_changed(self, number):
|
||||
def on_screen_added(self, changed_screen):
|
||||
"""
|
||||
Called when the resolution of a screen has changed.
|
||||
Called when a screen has been added
|
||||
|
||||
``number``
|
||||
The number of the screen, which size has changed.
|
||||
:param changed_screen: The screen which has been plugged.
|
||||
"""
|
||||
log.info('screen_resolution_changed {number:d}'.format(number=number))
|
||||
number = len(self.screens)
|
||||
self.screens.append(Screen(number, changed_screen.geometry(),
|
||||
is_primary=self.application.primaryScreen() == changed_screen))
|
||||
changed_screen.geometryChanged.connect(self.screens[-1].on_geometry_changed)
|
||||
Registry().execute('config_screen_changed')
|
||||
|
||||
def on_screen_removed(self, removed_screen):
|
||||
"""
|
||||
Called when a screen has been removed.
|
||||
|
||||
:param changed_screen: The screen which has been unplugged.
|
||||
"""
|
||||
# Remove screens
|
||||
removed_screen_number = -1
|
||||
for screen in self.screens:
|
||||
if number == screen.number:
|
||||
screen.geometry = self.desktop.screenGeometry(number)
|
||||
screen.is_primary = self.desktop.primaryScreen() == number
|
||||
Registry().execute('config_screen_changed')
|
||||
break
|
||||
|
||||
def on_screen_count_changed(self, changed_screen=None):
|
||||
"""
|
||||
Called when a screen has been added or removed.
|
||||
|
||||
``changed_screen``
|
||||
The screen's number which has been (un)plugged.
|
||||
"""
|
||||
screen_count = self.desktop.screenCount()
|
||||
log.info('screen_count_changed {count:d}'.format(count=screen_count))
|
||||
# Update the list of screens
|
||||
self.update_screens()
|
||||
# Reload setting tabs to apply possible changes.
|
||||
# once the screen that must be removed has been found, update numbering
|
||||
if removed_screen_number >= 0:
|
||||
screen.number -= 1
|
||||
# find the screen that is removed
|
||||
if removed_screen.geometry() == screen.geometry:
|
||||
removed_screen_number = screen.number
|
||||
removed_screen_is_display = self.screens[removed_screen_number].is_display
|
||||
self.screens.pop(removed_screen_number)
|
||||
if removed_screen_is_display:
|
||||
self.find_new_display_screen()
|
||||
Registry().execute('config_screen_changed')
|
||||
|
||||
def on_primary_screen_changed(self):
|
||||
@ -356,5 +406,5 @@ class ScreenList(metaclass=Singleton):
|
||||
The primary screen has changed, let's sort it out and then notify everyone
|
||||
"""
|
||||
for screen in self.screens:
|
||||
screen.is_primary = self.desktop.primaryScreen() == screen.number
|
||||
screen.is_primary = self.desktop.primaryScreen().geometry() == screen.geometry
|
||||
Registry().execute('config_screen_changed')
|
||||
|
@ -521,6 +521,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
|
||||
# Media Manager
|
||||
self.media_tool_box.currentChanged.connect(self.on_media_tool_box_changed)
|
||||
self.application.set_busy_cursor()
|
||||
# Timestamp for latest screen-change-popup. Used to prevent spamming the user with popups
|
||||
self.screen_change_timestamp = None
|
||||
# Simple message boxes
|
||||
Registry().register_function('theme_update_global', self.default_theme_changed)
|
||||
Registry().register_function('config_screen_changed', self.screen_changed)
|
||||
@ -999,6 +1001,17 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, LogMixin, RegistryPropert
|
||||
self.setFocus()
|
||||
self.activateWindow()
|
||||
self.application.set_normal_cursor()
|
||||
# if a warning has been shown within the last 5 seconds, skip showing again to avoid spamming user,
|
||||
# also do not show if the settings window is visible
|
||||
if not self.settings_form.isVisible() and \
|
||||
not self.screen_change_timestamp or (datetime.now() - self.screen_change_timestamp).seconds > 5:
|
||||
QtWidgets.QMessageBox.warning(self, translate('OpenLP.MainWindow', 'Screen setup has changed'),
|
||||
translate('OpenLP.MainWindow',
|
||||
'The screen setup has changed. '
|
||||
'OpenLP will try to automatically select a display screen, but '
|
||||
'you should consider updating the screen settings.'),
|
||||
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
|
||||
self.screen_change_timestamp = datetime.now()
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""
|
||||
|
@ -661,9 +661,16 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
|
||||
"""
|
||||
Settings dialog has changed the screen size of adjust output and screen previews.
|
||||
"""
|
||||
size = self.screens.current.display_geometry.size()
|
||||
if self.is_live and self.displays:
|
||||
for display in self.displays:
|
||||
display.resize(self.screens.current.display_geometry.size())
|
||||
display.resize(size)
|
||||
old_preview_width = self.preview_display.size().width()
|
||||
scale = old_preview_width / size.width()
|
||||
new_preview_size = size * scale
|
||||
self.ratio = self.screens.current.display_geometry.width() / self.screens.current.display_geometry.height()
|
||||
self.preview_display.resize(new_preview_size)
|
||||
self.slide_layout.set_aspect_ratio(self.ratio)
|
||||
|
||||
def __add_actions_to_widget(self, widget):
|
||||
"""
|
||||
|
@ -60,8 +60,10 @@ class AspectRatioLayout(QtWidgets.QLayout):
|
||||
|
||||
:param float aspect_ratio: The aspect ratio to set
|
||||
"""
|
||||
# TODO: Update the layout/widget if this changes
|
||||
self._aspect_ratio = aspect_ratio
|
||||
# Update the layout/widget
|
||||
geo = self.geometry()
|
||||
self.setGeometry(geo)
|
||||
|
||||
aspect_ratio = property(get_aspect_ratio, set_aspect_ratio)
|
||||
|
||||
|
@ -74,17 +74,15 @@ def test_create_screen_list(mocked_screens, settings):
|
||||
"""
|
||||
Create the screen list
|
||||
"""
|
||||
# GIVEN: Mocked desktop
|
||||
mocked_desktop = MagicMock()
|
||||
mocked_desktop.screenCount.return_value = 2
|
||||
mocked_desktop.primaryScreen.return_value = 0
|
||||
mocked_screens.return_value = [
|
||||
MagicMock(**{'geometry.return_value': QtCore.QRect(0, 0, 1024, 768)}),
|
||||
MagicMock(**{'geometry.return_value': QtCore.QRect(1024, 0, 1024, 768)})
|
||||
]
|
||||
# GIVEN: Mocked application
|
||||
mocked_application = MagicMock()
|
||||
mocked_screen1 = MagicMock(**{'geometry.return_value': QtCore.QRect(0, 0, 1024, 768)})
|
||||
mocked_screen2 = MagicMock(**{'geometry.return_value': QtCore.QRect(1024, 0, 1024, 768)})
|
||||
mocked_application.screens.return_value = [mocked_screen1, mocked_screen2]
|
||||
mocked_application.primaryScreen.return_value = mocked_screen1
|
||||
|
||||
# WHEN: create() is called
|
||||
screen_list = ScreenList.create(mocked_desktop)
|
||||
screen_list = ScreenList.create(mocked_application)
|
||||
|
||||
# THEN: The correct screens have been set up
|
||||
assert screen_list.screens[0].number == 0
|
||||
|
@ -47,7 +47,7 @@ def _create_mock_action(parent, name, **kwargs):
|
||||
|
||||
|
||||
@pytest.yield_fixture()
|
||||
def main_window(state, settings):
|
||||
def main_window(state, settings, mocked_qapp):
|
||||
app = Registry().get('application')
|
||||
app.set_busy_cursor = MagicMock()
|
||||
app.set_normal_cursor = MagicMock()
|
||||
@ -59,11 +59,13 @@ def main_window(state, settings):
|
||||
mocked_add_toolbar_action.side_effect = _create_mock_action
|
||||
renderer_patcher = patch('openlp.core.display.render.Renderer')
|
||||
renderer_patcher.start()
|
||||
mocked_desktop = MagicMock()
|
||||
mocked_desktop.screenCount.return_value = 1
|
||||
mocked_desktop.screenGeometry.return_value = QtCore.QRect(0, 0, 1024, 768)
|
||||
mocked_desktop.primaryScreen.return_value = 1
|
||||
ScreenList.create(mocked_desktop)
|
||||
mocked_screen = MagicMock()
|
||||
mocked_screen.geometry.return_value = QtCore.QRect(0, 0, 1024, 768)
|
||||
mocked_qapp.screens = MagicMock()
|
||||
mocked_qapp.screens.return_value = [mocked_screen]
|
||||
mocked_qapp.primaryScreen = MagicMock()
|
||||
mocked_qapp.primaryScreen.return_value = mocked_screen
|
||||
ScreenList.create(mocked_qapp)
|
||||
mainwindow = MainWindow()
|
||||
yield mainwindow
|
||||
del mainwindow
|
||||
|
@ -38,14 +38,15 @@ from tests.utils.constants import RESOURCE_PATH
|
||||
|
||||
|
||||
@pytest.yield_fixture()
|
||||
def pdf_env(settings, mock_plugin):
|
||||
def pdf_env(settings, mock_plugin, mocked_qapp):
|
||||
temp_folder_path = Path(mkdtemp())
|
||||
thumbnail_folder_path = Path(mkdtemp())
|
||||
desktop = MagicMock()
|
||||
desktop.primaryScreen.return_value = SCREEN['primary']
|
||||
desktop.screenCount.return_value = SCREEN['number']
|
||||
desktop.screenGeometry.return_value = SCREEN['size']
|
||||
ScreenList.create(desktop)
|
||||
mocked_screen = MagicMock()
|
||||
mocked_screen.geometry.return_value = QtCore.QRect(0, 0, 1024, 768)
|
||||
mocked_qapp.screens.return_value = [mocked_screen]
|
||||
mocked_qapp.primaryScreen = MagicMock()
|
||||
mocked_qapp.primaryScreen.return_value = mocked_screen
|
||||
ScreenList.create(mocked_qapp)
|
||||
yield settings, mock_plugin, temp_folder_path, thumbnail_folder_path
|
||||
rmtree(thumbnail_folder_path)
|
||||
rmtree(temp_folder_path)
|
||||
|
Loading…
Reference in New Issue
Block a user