Now launch game process no longer blocking main thread.
This commit is contained in:
+101
-52
@@ -1,13 +1,13 @@
|
||||
from pathlib import Path
|
||||
|
||||
from PySide6.QtCore import Qt, Signal
|
||||
from PySide6.QtCore import Qt, Signal, Slot, QTimer
|
||||
from PySide6.QtGui import QIcon, QMouseEvent, QHideEvent, QPixmap, QPainter
|
||||
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, QScrollArea, QFrame,
|
||||
QSizePolicy, QApplication)
|
||||
|
||||
from manager.game import LaunchManager
|
||||
from manager.game import LaunchManager, LaunchResult
|
||||
from core_lib.game.version_info import LATEST_VERSION_ALIASES
|
||||
from manager.profile import ProfileSummary
|
||||
from manager.profile import ProfileSummary, LaunchProfile, ProfileManager
|
||||
from manager.widgets import AskForRequest, WidgetManager
|
||||
from pages.process_log import ProcessLogWindow
|
||||
|
||||
@@ -161,6 +161,9 @@ class ProfilePopup(QFrame):
|
||||
)
|
||||
|
||||
def load_profiles(self, profiles: list[ProfileSummary]) -> None:
|
||||
# Clean old profiles
|
||||
self.clean_profiles()
|
||||
|
||||
for profile in profiles:
|
||||
icon_path = profile.icon
|
||||
|
||||
@@ -176,6 +179,14 @@ class ProfilePopup(QFrame):
|
||||
item.set_icon(icon_path)
|
||||
self.content_layout.addWidget(item)
|
||||
|
||||
def clean_profiles(self) -> None:
|
||||
while self.content_layout.count():
|
||||
layout_item = self.content_layout.takeAt(0)
|
||||
widget = layout_item.widget()
|
||||
|
||||
if widget is not None:
|
||||
widget.hide()
|
||||
widget.deleteLater()
|
||||
|
||||
def hideEvent(self, event: QHideEvent) -> None:
|
||||
self.closed.emit()
|
||||
@@ -187,7 +198,7 @@ class LaunchProfilePage(QWidget):
|
||||
super(LaunchProfilePage, self).__init__(parent)
|
||||
self.app = app
|
||||
self.widget_mgr: WidgetManager = app.widget_manager
|
||||
self.profile_manager = app.profile_manager
|
||||
self.profile_manager: ProfileManager = app.profile_manager
|
||||
self.game_manager = app.game_manager
|
||||
self.launch_manager: LaunchManager = self.game_manager.launch
|
||||
self.process_log_windows: list[ProcessLogWindow] = []
|
||||
@@ -271,7 +282,15 @@ class LaunchProfilePage(QWidget):
|
||||
|
||||
self.app.apply_qss(Path("profile.qss"), self.setStyleSheet)
|
||||
|
||||
self.load_profiles()
|
||||
# Handle launch() result
|
||||
self.launch_manager.signal.finished.connect(
|
||||
self.launch_finished,
|
||||
Qt.ConnectionType.QueuedConnection,
|
||||
)
|
||||
|
||||
self.profile_manager.profiles_changed.connect(
|
||||
self.load_profiles,
|
||||
)
|
||||
|
||||
class ProfileBackgroundFrame(QFrame):
|
||||
def __init__(self, image_path, parent=None):
|
||||
@@ -294,6 +313,51 @@ class LaunchProfilePage(QWidget):
|
||||
y = (self.height() - scaled.height()) // 2
|
||||
painter.drawPixmap(x, y, scaled)
|
||||
|
||||
@Slot(object, object)
|
||||
def launch_finished(self, launch_profile: LaunchProfile, result: LaunchResult) -> None:
|
||||
"""
|
||||
Handle launch finished signal
|
||||
:param launch_profile:
|
||||
:param result:
|
||||
:return:
|
||||
"""
|
||||
if not result.success:
|
||||
self.status_label.setText("Launch Failed")
|
||||
self.widget_mgr.signal.show_error_message.emit(
|
||||
f"Unable to launch profile "
|
||||
f"{launch_profile.display_name}: "
|
||||
f"{result.error_message}"
|
||||
)
|
||||
return
|
||||
|
||||
# Create log view
|
||||
log_window = ProcessLogWindow(
|
||||
result.process,
|
||||
launch_profile.profile_id,
|
||||
title=(
|
||||
f"Minecraft Log - {launch_profile.display_name} "
|
||||
f"({launch_profile.version_id})"
|
||||
),
|
||||
parent=None,
|
||||
finished_callback=self.launch_manager.profile_finished,
|
||||
)
|
||||
|
||||
for warning in result.warnings:
|
||||
log_window.append_message(
|
||||
f"[launcher warning] {warning}"
|
||||
)
|
||||
|
||||
self.process_log_windows.append(log_window)
|
||||
log_window.show()
|
||||
|
||||
self.status_label.setText("Launched!")
|
||||
|
||||
# Cleanup for status label
|
||||
timer = QTimer(self)
|
||||
timer.setSingleShot(True)
|
||||
timer.timeout.connect(lambda: self.status_label.setText("Select a profile to launch"))
|
||||
timer.start(3000)
|
||||
|
||||
def load_profiles(self):
|
||||
profiles: list[ProfileSummary] = self.profile_manager.list_profiles()
|
||||
self.profile_popup.load_profiles(profiles)
|
||||
@@ -363,54 +427,39 @@ class LaunchProfilePage(QWidget):
|
||||
self.profile_button.set_popup_open(False)
|
||||
|
||||
def launch_profile(self) -> None:
|
||||
try:
|
||||
profile_id = self.profile_button.property("profile_id")
|
||||
self.status_label.setText("Preparing to launch...")
|
||||
launch_profile = self.app.profile_manager.get_launch_profile(profile_id)
|
||||
profile_id = self.profile_button.property("profile_id")
|
||||
|
||||
if launch_profile is None:
|
||||
self.status_label.setText("Unable to load the selected profile.")
|
||||
if profile_id is None:
|
||||
self.widget_mgr.signal.show_warning_message.emit(
|
||||
"There is no profile is selected."
|
||||
" Please create one first."
|
||||
)
|
||||
return
|
||||
|
||||
self.status_label.setText("Preparing to launch...")
|
||||
launch_profile = self.app.profile_manager.get_launch_profile(profile_id)
|
||||
|
||||
if launch_profile is None:
|
||||
self.status_label.setText("Unable to load the selected profile.")
|
||||
return
|
||||
|
||||
if self.launch_manager.is_profile_running(launch_profile.profile_id):
|
||||
request = AskForRequest(
|
||||
"Launch Request",
|
||||
"Target profile {} is running. Are you sure you want to launch it again?".format(
|
||||
launch_profile.display_name
|
||||
),
|
||||
)
|
||||
self.widget_mgr.signal.askyesno.emit(request)
|
||||
|
||||
if not request.wait(60):
|
||||
self.widget_mgr.signal.show_error_message.emit(
|
||||
"Time out waiting for request for launch."
|
||||
)
|
||||
return
|
||||
|
||||
if self.launch_manager.is_profile_running(launch_profile.profile_id):
|
||||
request = AskForRequest(
|
||||
"Launch Request",
|
||||
"Target profile {} is running. Are you sure you want to launch it again?".format(
|
||||
launch_profile.display_name
|
||||
),
|
||||
)
|
||||
self.widget_mgr.signal.askyesno.emit(request)
|
||||
if not request.result() is True:
|
||||
return
|
||||
|
||||
if not request.wait(60):
|
||||
self.widget_mgr.signal.show_error_message.emit(
|
||||
"Time out waiting for request for launch."
|
||||
)
|
||||
return
|
||||
|
||||
if not request.result() is True:
|
||||
return
|
||||
|
||||
result = self.launch_manager.launch(launch_profile)
|
||||
|
||||
if result.success:
|
||||
self.status_label.setText("Launched!")
|
||||
log_window = ProcessLogWindow(
|
||||
result.process,
|
||||
launch_profile.profile_id,
|
||||
title=f"Minecraft Log - {launch_profile.display_name} ({launch_profile.version_id})",
|
||||
parent=None,
|
||||
finished_callback=self.launch_manager.profile_finished,
|
||||
)
|
||||
for warning in result.warnings:
|
||||
log_window.append_message(f"[launcher warning] {warning}")
|
||||
self.process_log_windows.append(log_window)
|
||||
log_window.show()
|
||||
else:
|
||||
self.widget_mgr.signal.show_error_message.emit(
|
||||
"Unable to launch profile {}: {}".format(
|
||||
launch_profile.display_name,
|
||||
result.error_message,
|
||||
)
|
||||
)
|
||||
finally:
|
||||
self.status_label.setText("Select a profile to launch")
|
||||
self.launch_manager.start_launch_task(launch_profile)
|
||||
# The log view window creation process has been moved to the method self.launch_finished, move to there!
|
||||
|
||||
Reference in New Issue
Block a user