chore: use login1 D-Bus for system actions #231
No files matched your search
+1
-1
@@ -28,8 +28,8 @@
|
||||
- Обновлён перевод на Китайский (упрощённый) `https://translate.codeberg.org/projects/portprotonqt/portprotonqt/zh_Hans/`
|
||||
- Возвращено отображение нативных Linux-игр в библиотеке Steam без отображения саундтреков
|
||||
- После создания или удаления ярлыков меню обновляется база desktop-файлов
|
||||
|
||||
### Fixed
|
||||
- Системные действия в режиме `--ppqtos` переведены на `systemctl` и `loginctl`
|
||||
- Исправлен ввод кириллицы при поиске игр
|
||||
- Поиск игр ограничен названиями без совпадений по описаниям
|
||||
- Исправлено состояние кнопки остановки при переключении детальной страницы на компактный вид
|
||||
|
||||
@@ -46,6 +46,7 @@ logger = get_logger(__name__)
|
||||
|
||||
AUDIO_MAX_VOLUME = 150
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from PySide6.QtWidgets import QMainWindow
|
||||
|
||||
@@ -896,25 +897,29 @@ class MainWindowSystemTabMixin(_MainWindowTypingBase):
|
||||
layout.addLayout(buttons_layout)
|
||||
layout.addStretch()
|
||||
|
||||
def _runLoginctlAction(self, action: str) -> None:
|
||||
args = [action]
|
||||
if action == "terminate-session":
|
||||
args.append("self")
|
||||
if QProcess.startDetached("loginctl", args):
|
||||
def _runSystemAction(self, action: str) -> None:
|
||||
command = "systemctl" if os.path.isdir("/run/systemd/system") else "loginctl"
|
||||
if QProcess.startDetached(command, [action]):
|
||||
return
|
||||
logger.error("Failed to execute loginctl %s", " ".join(args))
|
||||
logger.error("Failed to execute %s %s", command, action)
|
||||
|
||||
def rebootSystem(self) -> None:
|
||||
self._runLoginctlAction("reboot")
|
||||
self._runSystemAction("reboot")
|
||||
|
||||
def shutdownSystem(self) -> None:
|
||||
self._runLoginctlAction("poweroff")
|
||||
self._runSystemAction("poweroff")
|
||||
|
||||
def suspendSystem(self) -> None:
|
||||
self._runLoginctlAction("suspend")
|
||||
self._runSystemAction("suspend")
|
||||
|
||||
def logoutSystem(self) -> None:
|
||||
self._runLoginctlAction("terminate-session")
|
||||
session_id = os.getenv("XDG_SESSION_ID")
|
||||
if not session_id:
|
||||
logger.error("Cannot log out: XDG_SESSION_ID is not set")
|
||||
return
|
||||
if QProcess.startDetached("loginctl", ["terminate-session", session_id]):
|
||||
return
|
||||
logger.error("Failed to execute loginctl terminate-session %s", session_id)
|
||||
|
||||
def loadSystemNetworks(self) -> None:
|
||||
self.runNetworkOperation("load")
|
||||
|
||||
@@ -20,10 +20,12 @@ from portprotonqt.portproton_api import remove_empty_custom_data_dirs
|
||||
import portprotonqt.tabs.autoinstall_tab as autoinstall_tab_module
|
||||
import portprotonqt.tabs.gog_tab as gog_tab_module
|
||||
import portprotonqt.tabs.library_tab as library_tab_module
|
||||
import portprotonqt.tabs.system_tab as system_tab_module
|
||||
from portprotonqt.tabs import (
|
||||
MainWindowAutoInstallTabMixin,
|
||||
MainWindowLibraryTabMixin,
|
||||
MainWindowSettingsTabMixin,
|
||||
MainWindowSystemTabMixin,
|
||||
MainWindowThemeTabMixin,
|
||||
MainWindowWineTabMixin,
|
||||
)
|
||||
@@ -1294,3 +1296,51 @@ def test_update_delete_missing_exe_button_visibility(tmp_path: Path) -> None:
|
||||
MainWindowLibraryTabMixin.updateDeleteMissingExeButton(window)
|
||||
|
||||
assert button.visible is True
|
||||
|
||||
|
||||
def test_system_action_uses_systemctl_with_systemd(monkeypatch: MonkeyPatch) -> None:
|
||||
calls: list[tuple[str, list[str]]] = []
|
||||
process = SimpleNamespace(startDetached=lambda *args: calls.append(args) or True)
|
||||
window = cast(MainWindowSystemTabMixin, SimpleNamespace())
|
||||
monkeypatch.setattr(system_tab_module.os.path, "isdir", lambda path: True)
|
||||
monkeypatch.setattr(system_tab_module, "QProcess", process)
|
||||
|
||||
MainWindowSystemTabMixin._runSystemAction(window, "reboot")
|
||||
|
||||
assert calls == [("systemctl", ["reboot"])]
|
||||
|
||||
|
||||
def test_system_action_uses_loginctl_with_elogind(monkeypatch: MonkeyPatch) -> None:
|
||||
calls: list[tuple[str, list[str]]] = []
|
||||
process = SimpleNamespace(startDetached=lambda *args: calls.append(args) or True)
|
||||
window = cast(MainWindowSystemTabMixin, SimpleNamespace())
|
||||
monkeypatch.setattr(system_tab_module.os.path, "isdir", lambda path: False)
|
||||
monkeypatch.setattr(system_tab_module, "QProcess", process)
|
||||
|
||||
MainWindowSystemTabMixin._runSystemAction(window, "suspend")
|
||||
|
||||
assert calls == [("loginctl", ["suspend"])]
|
||||
|
||||
|
||||
def test_logout_uses_current_session_id(monkeypatch: MonkeyPatch) -> None:
|
||||
calls: list[tuple[str, list[str]]] = []
|
||||
process = SimpleNamespace(startDetached=lambda *args: calls.append(args) or True)
|
||||
window = cast(MainWindowSystemTabMixin, SimpleNamespace())
|
||||
monkeypatch.setenv("XDG_SESSION_ID", "session-1")
|
||||
monkeypatch.setattr(system_tab_module, "QProcess", process)
|
||||
|
||||
MainWindowSystemTabMixin.logoutSystem(window)
|
||||
|
||||
assert calls == [("loginctl", ["terminate-session", "session-1"])]
|
||||
|
||||
|
||||
def test_logout_skips_without_session_id(monkeypatch: MonkeyPatch) -> None:
|
||||
calls: list[tuple[str, list[str]]] = []
|
||||
process = SimpleNamespace(startDetached=lambda *args: calls.append(args) or True)
|
||||
window = cast(MainWindowSystemTabMixin, SimpleNamespace())
|
||||
monkeypatch.delenv("XDG_SESSION_ID", raising=False)
|
||||
monkeypatch.setattr(system_tab_module, "QProcess", process)
|
||||
|
||||
MainWindowSystemTabMixin.logoutSystem(window)
|
||||
|
||||
assert calls == []
|
||||
Reference in new issue
Block a user