chore: use login1 D-Bus for system actions #231

Merged
Boria138 merged 1 commits from drop-loginctl into main 2026-07-28 16:29:56 +00:00
3 changed files with 66 additions and 11 deletions

No files matched your search

+1 -1
View File
@@ -28,8 +28,8 @@
- Обновлён перевод на Китайский (упрощённый) `https://translate.codeberg.org/projects/portprotonqt/portprotonqt/zh_Hans/`
- Возвращено отображение нативных Linux-игр в библиотеке Steam без отображения саундтреков
- После создания или удаления ярлыков меню обновляется база desktop-файлов
### Fixed
- Системные действия в режиме `--ppqtos` переведены на `systemctl` и `loginctl`
- Исправлен ввод кириллицы при поиске игр
- Поиск игр ограничен названиями без совпадений по описаниям
- Исправлено состояние кнопки остановки при переключении детальной страницы на компактный вид
+15 -10
View File
@@ -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")
+50
View File
@@ -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 == []