From c3c9b0f059e2d4e026df244bb1f860c4ca37efd8 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Wed, 13 Sep 2023 21:36:11 +0300
Subject: [PATCH] AccountWidget: Add a Quit button in the widget in case the
system tray
is unavailable (for example running in a gamescope session)
* Do not show the launch window while instantiating the application. This
probably was causing numerous issues because it was running outside of
the applications event loop. This also fixes the exit button on the login
dialog requiring `sys.exit()` to quit Rare. Now it goes through the
proper cleanup procedures.
* Make slot and signal names more uniform
* Fix a problem with RareCore connecting RareGames to the same signals
multiple times when the library was refreshed.
---
rare/components/__init__.py | 31 +++++++++++---------
rare/components/dialogs/launch_dialog.py | 4 +--
rare/components/dialogs/login/__init__.py | 35 +++++++++--------------
rare/components/main_window.py | 6 ++--
rare/components/tabs/__init__.py | 33 +++++++++++----------
rare/components/tabs/account/__init__.py | 25 +++++++++++++---
rare/shared/rare_core.py | 2 +-
7 files changed, 76 insertions(+), 60 deletions(-)
diff --git a/rare/components/__init__.py b/rare/components/__init__.py
index f5af6d2d..8df9e34f 100644
--- a/rare/components/__init__.py
+++ b/rare/components/__init__.py
@@ -55,14 +55,9 @@ class Rare(RareApp):
self.launch_dialog: Optional[LaunchDialog] = None
self.timer: Optional[QTimer] = None
- # launch app
- self.launch_dialog = LaunchDialog(parent=None)
- self.launch_dialog.quit_app.connect(self.launch_dialog.close)
- self.launch_dialog.quit_app.connect(lambda x: sys.exit(x))
- self.launch_dialog.start_app.connect(self.start_app)
- self.launch_dialog.start_app.connect(self.launch_dialog.close)
-
- self.launch_dialog.login()
+ # This launches the application after it has been instantiated.
+ # The timer's signal will be serviced once we call `exec()` on the application
+ QTimer.singleShot(0, self.launch_app)
def poke_timer(self):
dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1]).replace(tzinfo=timezone.utc)
@@ -80,13 +75,23 @@ class Rare(RareApp):
return
self.poke_timer()
+ @pyqtSlot()
+ def launch_app(self):
+ self.launch_dialog = LaunchDialog(parent=None)
+ self.launch_dialog.exit_app.connect(self.launch_dialog.close)
+ self.launch_dialog.exit_app.connect(self.__on_exit_app)
+ self.launch_dialog.start_app.connect(self.start_app)
+ self.launch_dialog.start_app.connect(self.launch_dialog.close)
+ self.launch_dialog.login()
+
+ @pyqtSlot()
def start_app(self):
self.timer = QTimer()
self.timer.timeout.connect(self.re_login)
self.poke_timer()
self.main_window = MainWindow()
- self.main_window.exit_app.connect(self.on_exit_app)
+ self.main_window.exit_app.connect(self.__on_exit_app)
if not self.args.silent:
self.main_window.show()
@@ -94,11 +99,11 @@ class Rare(RareApp):
if self.args.test_start:
self.main_window.close()
self.main_window = None
- self.on_exit_app(0)
+ self.__on_exit_app(0)
@pyqtSlot()
@pyqtSlot(int)
- def on_exit_app(self, exit_code=0):
+ def __on_exit_app(self, exit_code=0):
threadpool = QThreadPool.globalInstance()
threadpool.waitForDone()
if self.timer is not None:
@@ -119,9 +124,7 @@ def start(args) -> int:
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
app = Rare(args)
- exit_code = app.exec_()
- # if not restart
- # restart app
+ exit_code = app.exec()
del app
if exit_code != -133742:
break
diff --git a/rare/components/dialogs/launch_dialog.py b/rare/components/dialogs/launch_dialog.py
index ee81fd12..ead7ac9d 100644
--- a/rare/components/dialogs/launch_dialog.py
+++ b/rare/components/dialogs/launch_dialog.py
@@ -14,7 +14,7 @@ logger = getLogger("LaunchDialog")
class LaunchDialog(QDialog):
- quit_app = pyqtSignal(int)
+ exit_app = pyqtSignal(int)
start_app = pyqtSignal()
def __init__(self, parent=None):
@@ -74,7 +74,7 @@ class LaunchDialog(QDialog):
self.show()
self.launch()
else:
- self.quit_app.emit(0)
+ self.exit_app.emit(0)
def launch(self):
self.progress_info.setText(self.tr("Preparing Rare"))
diff --git a/rare/components/dialogs/login/__init__.py b/rare/components/dialogs/login/__init__.py
index 66a1f346..f9ca2b59 100644
--- a/rare/components/dialogs/login/__init__.py
+++ b/rare/components/dialogs/login/__init__.py
@@ -1,7 +1,6 @@
-from dataclasses import dataclass
from logging import getLogger
-from PyQt5.QtCore import Qt
+from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QLayout, QDialog, QMessageBox, QFrame
from legendary.core import LegendaryCore
@@ -15,13 +14,6 @@ from .import_login import ImportLogin
logger = getLogger("LoginDialog")
-@dataclass
-class LoginPages:
- landing: int
- browser: int
- import_egl: int
-
-
class LandingPage(QFrame):
def __init__(self, parent=None):
super(LandingPage, self).__init__(parent=parent)
@@ -31,8 +23,7 @@ class LandingPage(QFrame):
class LoginDialog(QDialog):
- logged_in: bool = False
- pages = LoginPages(landing=0, browser=1, import_egl=2)
+ exit_app: pyqtSignal = pyqtSignal(int)
def __init__(self, core: LegendaryCore, parent=None):
super(LoginDialog, self).__init__(parent=parent)
@@ -51,6 +42,8 @@ class LoginDialog(QDialog):
self.ui = Ui_LoginDialog()
self.ui.setupUi(self)
+ self.logged_in: bool = False
+
self.core = core
self.args = ArgumentsSingleton()
@@ -59,16 +52,16 @@ class LoginDialog(QDialog):
self.ui.login_stack_layout.addWidget(self.login_stack)
self.landing_page = LandingPage(self.login_stack)
- self.login_stack.insertWidget(self.pages.landing, self.landing_page)
+ self.login_stack.insertWidget(0, self.landing_page)
self.browser_page = BrowserLogin(self.core, self.login_stack)
- self.login_stack.insertWidget(self.pages.browser, self.browser_page)
+ self.login_stack.insertWidget(1, self.browser_page)
self.browser_page.success.connect(self.login_successful)
self.browser_page.changed.connect(
lambda: self.ui.next_button.setEnabled(self.browser_page.is_valid())
)
self.import_page = ImportLogin(self.core, self.login_stack)
- self.login_stack.insertWidget(self.pages.import_egl, self.import_page)
+ self.login_stack.insertWidget(2, self.import_page)
self.import_page.success.connect(self.login_successful)
self.import_page.changed.connect(lambda: self.ui.next_button.setEnabled(self.import_page.is_valid()))
@@ -84,34 +77,34 @@ class LoginDialog(QDialog):
self.ui.back_button.clicked.connect(self.back_clicked)
self.ui.next_button.clicked.connect(self.next_clicked)
- self.login_stack.setCurrentIndex(self.pages.landing)
+ self.login_stack.setCurrentWidget(self.landing_page)
self.layout().setSizeConstraint(QLayout.SetFixedSize)
def back_clicked(self):
self.ui.back_button.setEnabled(False)
self.ui.next_button.setEnabled(True)
- self.login_stack.slideInIndex(self.pages.landing)
+ self.login_stack.slideInWidget(self.landing_page)
def browser_radio_clicked(self):
- self.login_stack.slideInIndex(self.pages.browser)
+ self.login_stack.slideInWidget(self.browser_page)
self.ui.back_button.setEnabled(True)
self.ui.next_button.setEnabled(False)
def import_radio_clicked(self):
- self.login_stack.slideInIndex(self.pages.import_egl)
+ self.login_stack.slideInWidget(self.import_page)
self.ui.back_button.setEnabled(True)
self.ui.next_button.setEnabled(self.import_page.is_valid())
def next_clicked(self):
- if self.login_stack.currentIndex() == self.pages.landing:
+ if self.login_stack.currentWidget() is self.landing_page:
if self.landing_page.ui.login_browser_radio.isChecked():
self.browser_radio_clicked()
if self.landing_page.ui.login_import_radio.isChecked():
self.import_radio_clicked()
- elif self.login_stack.currentIndex() == self.pages.browser:
+ elif self.login_stack.currentWidget() is self.browser_page:
self.browser_page.do_login()
- elif self.login_stack.currentIndex() == self.pages.import_egl:
+ elif self.login_stack.currentWidget() is self.import_page:
self.import_page.do_login()
def login(self):
diff --git a/rare/components/main_window.py b/rare/components/main_window.py
index 1efd4f66..318fc6b6 100644
--- a/rare/components/main_window.py
+++ b/rare/components/main_window.py
@@ -44,7 +44,7 @@ class MainWindow(QMainWindow):
self.setWindowTitle("Rare - GUI for legendary")
self.tab_widget = MainTabWidget(self)
- self.tab_widget.exit_app.connect(self.on_exit_app)
+ self.tab_widget.exit_app.connect(self.__on_exit_app)
self.setCentralWidget(self.tab_widget)
# Set up status bar stuff (jumping through a lot of hoops)
@@ -112,7 +112,7 @@ class MainWindow(QMainWindow):
self.timer.start()
self.tray_icon: TrayIcon = TrayIcon(self)
- self.tray_icon.exit_app.connect(self.on_exit_app)
+ self.tray_icon.exit_app.connect(self.__on_exit_app)
self.tray_icon.show_app.connect(self.show)
self.tray_icon.activated.connect(lambda r: self.toggle() if r == self.tray_icon.DoubleClick else None)
@@ -203,7 +203,7 @@ class MainWindow(QMainWindow):
@pyqtSlot()
@pyqtSlot(int)
- def on_exit_app(self, exit_code=0) -> None:
+ def __on_exit_app(self, exit_code=0) -> None:
self.__exit_code = exit_code
self.close()
diff --git a/rare/components/tabs/__init__.py b/rare/components/tabs/__init__.py
index 91a6d177..697984a6 100644
--- a/rare/components/tabs/__init__.py
+++ b/rare/components/tabs/__init__.py
@@ -51,7 +51,7 @@ class MainTabWidget(QTabWidget):
self.setTabEnabled(button_index, False)
self.account_widget = AccountWidget(self)
- self.account_widget.logout.connect(self.logout)
+ self.account_widget.exit_app.connect(self.__on_exit_app)
account_action = QWidgetAction(self)
account_action.setDefaultWidget(self.account_widget)
account_button = TabButtonWidget("mdi.account-circle", "Account", fallback_icon="fa.user")
@@ -93,25 +93,28 @@ class MainTabWidget(QTabWidget):
self.tab_bar.setMinimumWidth(self.width())
super(MainTabWidget, self).resizeEvent(event)
- @pyqtSlot()
- def logout(self):
+ @pyqtSlot(int)
+ def __on_exit_app(self, exit_code: int):
# FIXME: Don't allow logging out if there are active downloads
if self.downloads_tab.is_download_active:
QMessageBox.warning(
self,
- self.tr("Logout"),
- self.tr("There are active downloads. Stop them before logging out."),
+ self.tr("Quit") if exit_code == self.account_widget.ExitCodes.EXIT else self.tr("Logout"),
+ self.tr("There are active downloads. Stop them before trying to quit."),
)
return
# FIXME: End of FIXME
- reply = QMessageBox.question(
- self,
- self.tr("Logout"),
- self.tr("Do you really want to logout {}?").format(self.core.lgd.userdata.get("display_name")),
- buttons=(QMessageBox.Yes | QMessageBox.No),
- defaultButton=QMessageBox.No,
- )
+ if exit_code == self.account_widget.ExitCodes.LOGOUT:
+ reply = QMessageBox.question(
+ self,
+ self.tr("Logout"),
+ self.tr("Do you really want to logout {}?").format(self.core.lgd.userdata.get("display_name")),
+ buttons=(QMessageBox.Yes | QMessageBox.No),
+ defaultButton=QMessageBox.No,
+ )
- if reply == QMessageBox.Yes:
- self.core.lgd.invalidate_userdata()
- self.exit_app.emit(-133742) # restart exit code
+ if reply == QMessageBox.Yes:
+ self.core.lgd.invalidate_userdata()
+ else:
+ return
+ self.exit_app.emit(exit_code) # restart exit code
diff --git a/rare/components/tabs/account/__init__.py b/rare/components/tabs/account/__init__.py
index 91835cce..5806082b 100644
--- a/rare/components/tabs/account/__init__.py
+++ b/rare/components/tabs/account/__init__.py
@@ -1,15 +1,21 @@
import webbrowser
+from enum import IntEnum
-from PyQt5.QtCore import pyqtSignal
-from PyQt5.QtWidgets import QWidget, QVBoxLayout, QMessageBox, QLabel, QPushButton
+from PyQt5.QtCore import pyqtSignal, pyqtSlot
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
from rare.utils.misc import icon
class AccountWidget(QWidget):
+ exit_app: pyqtSignal = pyqtSignal(int)
logout: pyqtSignal = pyqtSignal()
+ class ExitCodes(IntEnum):
+ EXIT = 0
+ LOGOUT = -133742
+
def __init__(self, parent):
super(AccountWidget, self).__init__(parent=parent)
self.core = LegendaryCoreSingleton()
@@ -25,11 +31,22 @@ class AccountWidget(QWidget):
"https://www.epicgames.com/account/personal?productName=epicgames"
)
)
- self.logout_button = QPushButton(self.tr("Logout"))
- self.logout_button.clicked.connect(self.logout)
+ self.logout_button = QPushButton(self.tr("Logout"), parent=self)
+ self.logout_button.clicked.connect(self.__on_logout)
+ self.quit_button = QPushButton(self.tr("Quit"), parent=self)
+ self.quit_button.clicked.connect(self.__on_quit)
layout = QVBoxLayout(self)
layout.addWidget(QLabel(self.tr("Account")))
layout.addWidget(QLabel(self.tr("Logged in as {}").format(username)))
layout.addWidget(self.open_browser)
layout.addWidget(self.logout_button)
+ layout.addWidget(self.quit_button)
+
+ @pyqtSlot()
+ def __on_quit(self):
+ self.exit_app.emit(AccountWidget.ExitCodes.EXIT)
+
+ @pyqtSlot()
+ def __on_logout(self):
+ self.exit_app.emit(AccountWidget.ExitCodes.LOGOUT)
diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py
index 69132637..e4cb2a0e 100644
--- a/rare/shared/rare_core.py
+++ b/rare/shared/rare_core.py
@@ -179,8 +179,8 @@ class RareCore(QObject):
del self.__args
self.__args = None
+ del self.__eos_overlay
RareCore.__instance = None
-
super(RareCore, self).deleteLater()
def __validate_install(self, rgame: RareGame):