From 17011820de76eda92d5b12112850de4dfdc91f1b Mon Sep 17 00:00:00 2001 From: Johan Aberg Date: Wed, 20 Oct 2021 13:04:16 +1300 Subject: [PATCH] Fix crash if log window is open when entering mission. Use signal to append text to LogWindow to avoid crash from crossing thread boundaries. Change modal flag to enable interacting with LogWindow while the mission is running Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1493 --- qt_ui/widgets/QTopPanel.py | 4 ++-- qt_ui/windows/QLiberationWindow.py | 1 + qt_ui/windows/QWaitingForMissionResultWindow.py | 17 ++++++++++++----- qt_ui/windows/logs/QLogsWindow.py | 13 +++++++++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/qt_ui/widgets/QTopPanel.py b/qt_ui/widgets/QTopPanel.py index d94f2911..81083818 100644 --- a/qt_ui/widgets/QTopPanel.py +++ b/qt_ui/widgets/QTopPanel.py @@ -287,8 +287,8 @@ class QTopPanel(QFrame): ) unit_map = self.game.initiate_event(game_event) - waiting = QWaitingForMissionResultWindow(game_event, self.game, unit_map) - waiting.show() + waiting = QWaitingForMissionResultWindow(game_event, self.game, unit_map, self) + waiting.exec_() def budget_update(self, game: Game): self.budgetBox.setGame(game) diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py index 5fa02dac..ed4f3d00 100644 --- a/qt_ui/windows/QLiberationWindow.py +++ b/qt_ui/windows/QLiberationWindow.py @@ -387,5 +387,6 @@ class QLiberationWindow(QMainWindow): ) if result == QMessageBox.Yes: super().closeEvent(event) + self.dialog = None else: event.ignore() diff --git a/qt_ui/windows/QWaitingForMissionResultWindow.py b/qt_ui/windows/QWaitingForMissionResultWindow.py index 0361fcaa..8eeda23d 100644 --- a/qt_ui/windows/QWaitingForMissionResultWindow.py +++ b/qt_ui/windows/QWaitingForMissionResultWindow.py @@ -2,11 +2,11 @@ from __future__ import annotations import json import os -from typing import Sized +from typing import Sized, Optional from PySide2 import QtCore from PySide2.QtCore import QObject, Qt, Signal -from PySide2.QtGui import QIcon, QMovie, QPixmap +from PySide2.QtGui import QIcon, QMovie, QPixmap, QWindow from PySide2.QtWidgets import ( QDialog, QFileDialog, @@ -17,6 +17,7 @@ from PySide2.QtWidgets import ( QMessageBox, QPushButton, QTextBrowser, + QWidget, ) from jinja2 import Environment, FileSystemLoader, select_autoescape @@ -49,9 +50,15 @@ DebriefingFileWrittenSignal() class QWaitingForMissionResultWindow(QDialog): - def __init__(self, gameEvent: Event, game: Game, unit_map: UnitMap) -> None: - super(QWaitingForMissionResultWindow, self).__init__() - self.setModal(True) + def __init__( + self, + gameEvent: Event, + game: Game, + unit_map: UnitMap, + parent: Optional[QWidget] = None, + ) -> None: + super(QWaitingForMissionResultWindow, self).__init__(parent=parent) + self.setWindowModality(QtCore.Qt.WindowModal) self.gameEvent = gameEvent self.game = game self.unit_map = unit_map diff --git a/qt_ui/windows/logs/QLogsWindow.py b/qt_ui/windows/logs/QLogsWindow.py index 936261a1..47bc872e 100644 --- a/qt_ui/windows/logs/QLogsWindow.py +++ b/qt_ui/windows/logs/QLogsWindow.py @@ -1,18 +1,21 @@ import logging import typing +from PySide2.QtCore import Signal from PySide2.QtWidgets import ( QDialog, QPlainTextEdit, QVBoxLayout, QPushButton, ) -from PySide2.QtGui import QTextCursor +from PySide2.QtGui import QTextCursor, QIcon from qt_ui.logging_handler import HookableInMemoryHandler class QLogsWindow(QDialog): + appendLogSignal = Signal(str) + vbox: QVBoxLayout textbox: QPlainTextEdit clear_button: QPushButton @@ -24,6 +27,7 @@ class QLogsWindow(QDialog): self.setWindowTitle("Logs") self.setMinimumSize(400, 100) self.resize(1000, 450) + self.setWindowIcon(QIcon("./resources/icon.png")) self.vbox = QVBoxLayout() self.setLayout(self.vbox) @@ -44,6 +48,8 @@ class QLogsWindow(QDialog): self.clear_button.clicked.connect(self.clearLogs) self.vbox.addWidget(self.clear_button) + self.appendLogSignal.connect(self.appendLog) + self._logging_handler = None logger = logging.getLogger() for handler in logger.handlers: @@ -53,7 +59,10 @@ class QLogsWindow(QDialog): if self._logging_handler is not None: self.textbox.setPlainText(self._logging_handler.log) self.textbox.moveCursor(QTextCursor.End) - self._logging_handler.setHook(self.appendLog) + # The Handler might be called from a different thread, + # so use signal/slot to properly handle the event in the main thread. + # https://github.com/dcs-liberation/dcs_liberation/issues/1493 + self._logging_handler.setHook(self.appendLogSignal.emit) else: self.textbox.setPlainText("WARNING: logging not initialized!")