forked from Boria138/PortProtonQt
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			92d52938a9
			...
			14b5d6ce6f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 14b5d6ce6f | |||
| 90e27a49ca | |||
| 08c154ade6 | |||
| 6efaff284f | 
| @@ -10,7 +10,7 @@ | |||||||
| - Начальная поддержка EGS (Без EOS, скачивания игр и запуска игр из сторонних магазинов) | - Начальная поддержка EGS (Без EOS, скачивания игр и запуска игр из сторонних магазинов) | ||||||
| - Автодополнение bash для комманды portprotonqt | - Автодополнение bash для комманды portprotonqt | ||||||
| - Поддержка геймпадов в диалоге выбора игры | - Поддержка геймпадов в диалоге выбора игры | ||||||
| - Быстрый запуск игры через контекстное меню | - Быстрый запуск и остановка игры через контекстное меню | ||||||
| - Иконки в контекстом меню | - Иконки в контекстом меню | ||||||
|  |  | ||||||
| ### Changed | ### Changed | ||||||
|   | |||||||
| @@ -20,9 +20,9 @@ Current translation status: | |||||||
|  |  | ||||||
| | Locale | Progress | Translated | | | Locale | Progress | Translated | | ||||||
| | :----- | -------: | ---------: | | | :----- | -------: | ---------: | | ||||||
| | [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 of 183 | | | [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 of 185 | | ||||||
| | [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 of 183 | | | [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 of 185 | | ||||||
| | [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 183 of 183 | | | [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 185 of 185 | | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,9 +20,9 @@ | |||||||
|  |  | ||||||
| | Локаль | Прогресс | Переведено | | | Локаль | Прогресс | Переведено | | ||||||
| | :----- | -------: | ---------: | | | :----- | -------: | ---------: | | ||||||
| | [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 из 183 | | | [de_DE](./de_DE/LC_MESSAGES/messages.po) | 0% | 0 из 185 | | ||||||
| | [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 из 183 | | | [es_ES](./es_ES/LC_MESSAGES/messages.po) | 0% | 0 из 185 | | ||||||
| | [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 183 из 183 | | | [ru_RU](./ru_RU/LC_MESSAGES/messages.po) | 100% | 185 из 185 | | ||||||
|  |  | ||||||
| --- | --- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,6 +6,8 @@ import subprocess | |||||||
| import threading | import threading | ||||||
| import logging | import logging | ||||||
| import orjson | import orjson | ||||||
|  | import psutil | ||||||
|  | import signal | ||||||
| from PySide6.QtWidgets import QMessageBox, QDialog, QMenu | from PySide6.QtWidgets import QMessageBox, QDialog, QMenu | ||||||
| from PySide6.QtCore import QUrl, QPoint, QObject, Signal, Qt | from PySide6.QtCore import QUrl, QPoint, QObject, Signal, Qt | ||||||
| from PySide6.QtGui import QDesktopServices, QIcon | from PySide6.QtGui import QDesktopServices, QIcon | ||||||
| @@ -120,6 +122,35 @@ class ContextMenuManager: | |||||||
|             logger.error("Failed to read installed.json: %s", e) |             logger.error("Failed to read installed.json: %s", e) | ||||||
|             return False |             return False | ||||||
|  |  | ||||||
|  |     def _is_game_running(self, game_card) -> bool: | ||||||
|  |         """ | ||||||
|  |         Check if the game associated with the game_card is currently running. | ||||||
|  |  | ||||||
|  |         Args: | ||||||
|  |             game_card: The GameCard instance containing game data. | ||||||
|  |  | ||||||
|  |         Returns: | ||||||
|  |             bool: True if the game is running, False otherwise. | ||||||
|  |         """ | ||||||
|  |         if game_card.game_source == "epic": | ||||||
|  |             exe_path = get_egs_executable(game_card.appid, self.legendary_config_path) | ||||||
|  |             if not exe_path or not os.path.exists(exe_path): | ||||||
|  |                 return False | ||||||
|  |             current_exe = os.path.basename(exe_path) | ||||||
|  |         else: | ||||||
|  |             exec_line = self._get_exec_line(game_card.name, game_card.exec_line) | ||||||
|  |             if not exec_line: | ||||||
|  |                 return False | ||||||
|  |             exe_path = self._parse_exe_path(exec_line, game_card.name) | ||||||
|  |             if not exe_path: | ||||||
|  |                 return False | ||||||
|  |             current_exe = os.path.basename(exe_path) | ||||||
|  |  | ||||||
|  |         # Check if the current_exe matches the target_exe in MainWindow | ||||||
|  |         if hasattr(self.parent, 'target_exe') and self.parent.target_exe == current_exe: | ||||||
|  |             return True | ||||||
|  |         return False | ||||||
|  |  | ||||||
|     def show_context_menu(self, game_card, pos: QPoint): |     def show_context_menu(self, game_card, pos: QPoint): | ||||||
|         """ |         """ | ||||||
|         Show the context menu for a game card at the specified position. |         Show the context menu for a game card at the specified position. | ||||||
| @@ -140,7 +171,11 @@ class ContextMenuManager: | |||||||
|         menu = QMenu(self.parent) |         menu = QMenu(self.parent) | ||||||
|         menu.setStyleSheet(self.theme.CONTEXT_MENU_STYLE) |         menu.setStyleSheet(self.theme.CONTEXT_MENU_STYLE) | ||||||
|  |  | ||||||
|         launch_action = menu.addAction(get_safe_icon("play"), _("Launch Game")) |         # Check if the game is running | ||||||
|  |         is_running = self._is_game_running(game_card) | ||||||
|  |         action_text = _("Stop Game") if is_running else _("Launch Game") | ||||||
|  |         action_icon = "stop" if is_running else "play" | ||||||
|  |         launch_action = menu.addAction(get_safe_icon(action_icon), action_text) | ||||||
|         launch_action.triggered.connect( |         launch_action.triggered.connect( | ||||||
|             lambda: self._launch_game(game_card) |             lambda: self._launch_game(game_card) | ||||||
|         ) |         ) | ||||||
| @@ -153,7 +188,7 @@ class ContextMenuManager: | |||||||
|         favorite_action.triggered.connect(lambda: self.toggle_favorite(game_card, not is_favorite)) |         favorite_action.triggered.connect(lambda: self.toggle_favorite(game_card, not is_favorite)) | ||||||
|  |  | ||||||
|         if game_card.game_source == "epic": |         if game_card.game_source == "epic": | ||||||
|             import_action = menu.addAction(get_safe_icon("import"), _("Import to Legendary")) |             import_action = menu.addAction(get_safe_icon("epic_games"), _("Import to Legendary")) | ||||||
|             import_action.triggered.connect( |             import_action.triggered.connect( | ||||||
|                 lambda: self.import_to_legendary(game_card.name, game_card.appid) |                 lambda: self.import_to_legendary(game_card.name, game_card.appid) | ||||||
|             ) |             ) | ||||||
| @@ -240,13 +275,44 @@ class ContextMenuManager: | |||||||
|  |  | ||||||
|     def _launch_game(self, game_card): |     def _launch_game(self, game_card): | ||||||
|         """ |         """ | ||||||
|         Launch a game using a validated exec_line, handling EGS games specifically. |         Launch or stop a game based on its current state. | ||||||
|  |  | ||||||
|         Args: |         Args: | ||||||
|             game_card: The GameCard instance containing game data. |             game_card: The GameCard instance containing game data. | ||||||
|         """ |         """ | ||||||
|         if not self._check_portproton(): |         if not self._check_portproton(): | ||||||
|             return |             return | ||||||
|  |  | ||||||
|  |         # Check if the game is running | ||||||
|  |         if self._is_game_running(game_card): | ||||||
|  |             # Stop the game | ||||||
|  |             if hasattr(self.parent, 'game_processes') and self.parent.game_processes: | ||||||
|  |                 for proc in self.parent.game_processes: | ||||||
|  |                     try: | ||||||
|  |                         parent = psutil.Process(proc.pid) | ||||||
|  |                         children = parent.children(recursive=True) | ||||||
|  |                         for child in children: | ||||||
|  |                             try: | ||||||
|  |                                 child.terminate() | ||||||
|  |                             except psutil.NoSuchProcess: | ||||||
|  |                                 pass | ||||||
|  |                         psutil.wait_procs(children, timeout=5) | ||||||
|  |                         for child in children: | ||||||
|  |                             if child.is_running(): | ||||||
|  |                                 child.kill() | ||||||
|  |                         os.killpg(os.getpgid(proc.pid), signal.SIGTERM) | ||||||
|  |                     except psutil.NoSuchProcess: | ||||||
|  |                         pass | ||||||
|  |                 self.parent.game_processes = [] | ||||||
|  |                 self.parent.resetPlayButton() | ||||||
|  |                 if hasattr(self.parent, 'checkProcessTimer') and self.parent.checkProcessTimer is not None: | ||||||
|  |                     self.parent.checkProcessTimer.stop() | ||||||
|  |                     self.parent.checkProcessTimer.deleteLater() | ||||||
|  |                     self.parent.checkProcessTimer = None | ||||||
|  |                 self._show_status_message(_("Stopped '{game_name}'").format(game_name=game_card.name)) | ||||||
|  |             return | ||||||
|  |  | ||||||
|  |         # Launch the game | ||||||
|         if game_card.game_source == "epic": |         if game_card.game_source == "epic": | ||||||
|             if not os.path.exists(self.legendary_path): |             if not os.path.exists(self.legendary_path): | ||||||
|                 self.signals.show_warning_dialog.emit( |                 self.signals.show_warning_dialog.emit( | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| @@ -9,7 +9,7 @@ msgid "" | |||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PROJECT VERSION\n" | "Project-Id-Version: PROJECT VERSION\n" | ||||||
| "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | ||||||
| "POT-Creation-Date: 2025-07-01 15:54+0500\n" | "POT-Creation-Date: 2025-07-02 10:43+0500\n" | ||||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||||
| "Language: de_DE\n" | "Language: de_DE\n" | ||||||
| @@ -26,6 +26,9 @@ msgstr "" | |||||||
| msgid "PortProton is not found" | msgid "PortProton is not found" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Stop Game" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| msgid "Launch Game" | msgid "Launch Game" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -65,6 +68,10 @@ msgstr "" | |||||||
| msgid "Delete from PortProton" | msgid "Delete from PortProton" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #, python-brace-format | ||||||
|  | msgid "Stopped '{game_name}'" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "Legendary executable not found at {path}" | msgid "Legendary executable not found at {path}" | ||||||
| msgstr "" | msgstr "" | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| @@ -9,7 +9,7 @@ msgid "" | |||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PROJECT VERSION\n" | "Project-Id-Version: PROJECT VERSION\n" | ||||||
| "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | ||||||
| "POT-Creation-Date: 2025-07-01 15:54+0500\n" | "POT-Creation-Date: 2025-07-02 10:43+0500\n" | ||||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||||
| "Language: es_ES\n" | "Language: es_ES\n" | ||||||
| @@ -26,6 +26,9 @@ msgstr "" | |||||||
| msgid "PortProton is not found" | msgid "PortProton is not found" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Stop Game" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| msgid "Launch Game" | msgid "Launch Game" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -65,6 +68,10 @@ msgstr "" | |||||||
| msgid "Delete from PortProton" | msgid "Delete from PortProton" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #, python-brace-format | ||||||
|  | msgid "Stopped '{game_name}'" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "Legendary executable not found at {path}" | msgid "Legendary executable not found at {path}" | ||||||
| msgstr "" | msgstr "" | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ msgid "" | |||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PortProtonQt 0.1.1\n" | "Project-Id-Version: PortProtonQt 0.1.1\n" | ||||||
| "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | ||||||
| "POT-Creation-Date: 2025-07-01 15:54+0500\n" | "POT-Creation-Date: 2025-07-02 10:43+0500\n" | ||||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||||
| @@ -24,6 +24,9 @@ msgstr "" | |||||||
| msgid "PortProton is not found" | msgid "PortProton is not found" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Stop Game" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| msgid "Launch Game" | msgid "Launch Game" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
| @@ -63,6 +66,10 @@ msgstr "" | |||||||
| msgid "Delete from PortProton" | msgid "Delete from PortProton" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | #, python-brace-format | ||||||
|  | msgid "Stopped '{game_name}'" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "Legendary executable not found at {path}" | msgid "Legendary executable not found at {path}" | ||||||
| msgstr "" | msgstr "" | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| @@ -9,8 +9,8 @@ msgid "" | |||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PROJECT VERSION\n" | "Project-Id-Version: PROJECT VERSION\n" | ||||||
| "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | ||||||
| "POT-Creation-Date: 2025-07-01 15:54+0500\n" | "POT-Creation-Date: 2025-07-02 10:43+0500\n" | ||||||
| "PO-Revision-Date: 2025-07-01 15:54+0500\n" | "PO-Revision-Date: 2025-07-02 10:43+0500\n" | ||||||
| "Last-Translator: \n" | "Last-Translator: \n" | ||||||
| "Language: ru_RU\n" | "Language: ru_RU\n" | ||||||
| "Language-Team: ru_RU <LL@li.org>\n" | "Language-Team: ru_RU <LL@li.org>\n" | ||||||
| @@ -27,6 +27,9 @@ msgstr "Ошибка" | |||||||
| msgid "PortProton is not found" | msgid "PortProton is not found" | ||||||
| msgstr "PortProton не найден" | msgstr "PortProton не найден" | ||||||
|  |  | ||||||
|  | msgid "Stop Game" | ||||||
|  | msgstr "Остановить игру" | ||||||
|  |  | ||||||
| msgid "Launch Game" | msgid "Launch Game" | ||||||
| msgstr "Запустить игру" | msgstr "Запустить игру" | ||||||
|  |  | ||||||
| @@ -66,6 +69,10 @@ msgstr "Редактировать" | |||||||
| msgid "Delete from PortProton" | msgid "Delete from PortProton" | ||||||
| msgstr "Удалить из PortProton" | msgstr "Удалить из PortProton" | ||||||
|  |  | ||||||
|  | #, python-brace-format | ||||||
|  | msgid "Stopped '{game_name}'" | ||||||
|  | msgstr "Остановлен(а) '{game_name}'" | ||||||
|  |  | ||||||
| #, python-brace-format | #, python-brace-format | ||||||
| msgid "Legendary executable not found at {path}" | msgid "Legendary executable not found at {path}" | ||||||
| msgstr "Legendary не найден по пути {path}" | msgstr "Legendary не найден по пути {path}" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user