diff --git a/ameba_control_panel/app.py b/ameba_control_panel/app.py index 67ac83c..334858f 100644 --- a/ameba_control_panel/app.py +++ b/ameba_control_panel/app.py @@ -235,7 +235,13 @@ def _setup_logging() -> None: def _setup_linux_platform() -> None: """Ensure correct Qt platform plugin on Linux.""" import os - if sys.platform != "linux" or os.environ.get("QT_QPA_PLATFORM"): + if sys.platform != "linux": + return + # Disable xdg-desktop-portal and GVfs UDisks2 volume monitor to prevent + # file dialog crashes / hangs caused by D-Bus service timeouts. + os.environ.setdefault("QT_DISABLE_XDG_DESKTOP_PORTAL", "1") + os.environ.setdefault("GIO_USE_VOLUME_MONITOR", "unix") + if os.environ.get("QT_QPA_PLATFORM"): return if os.environ.get("WAYLAND_DISPLAY"): os.environ["QT_QPA_PLATFORM"] = "wayland;xcb" diff --git a/ameba_control_panel/controllers/device_tab_controller.py b/ameba_control_panel/controllers/device_tab_controller.py index f27a15a..4f72855 100644 --- a/ameba_control_panel/controllers/device_tab_controller.py +++ b/ameba_control_panel/controllers/device_tab_controller.py @@ -1,6 +1,7 @@ from __future__ import annotations import logging +import sys from pathlib import Path from typing import List, Optional @@ -274,7 +275,13 @@ class DeviceTabController(QObject): # Command list playback ---------------------------------------------------- def _browse_cmdlist(self) -> None: from PySide6.QtWidgets import QFileDialog - path, _ = QFileDialog.getOpenFileName(self.view, "Command list", "", "Text files (*.txt);;All files (*)") + dlg = QFileDialog(self.view, "Command list", "", "Text files (*.txt);;All files (*)") + dlg.setFileMode(QFileDialog.FileMode.ExistingFile) + if sys.platform == "linux": + dlg.setOption(QFileDialog.Option.DontUseNativeDialog, True) + if dlg.exec() != QFileDialog.DialogCode.Accepted or not dlg.selectedFiles(): + return + path = dlg.selectedFiles()[0] if path: self.view.cmdlist_path_edit.setText(path) self._save_session() diff --git a/ameba_control_panel/managers/flash_manager.py b/ameba_control_panel/managers/flash_manager.py index 5d8ad69..d65ce8d 100644 --- a/ameba_control_panel/managers/flash_manager.py +++ b/ameba_control_panel/managers/flash_manager.py @@ -1,6 +1,7 @@ from __future__ import annotations import logging +import sys from pathlib import Path from typing import Callable, List, Optional, Tuple, TYPE_CHECKING @@ -54,9 +55,12 @@ class FlashManager: self._connected_baud = baud def browse_file(self, title: str, target: QLineEdit, file_filter: str = "Binary files (*);;All files (*)") -> None: - path, _ = QFileDialog.getOpenFileName(self.view, title, "", file_filter) - if path: - target.setText(path) + dlg = QFileDialog(self.view, title, "", file_filter) + dlg.setFileMode(QFileDialog.FileMode.ExistingFile) + if sys.platform == "linux": + dlg.setOption(QFileDialog.Option.DontUseNativeDialog, True) + if dlg.exec() == QFileDialog.DialogCode.Accepted and dlg.selectedFiles(): + target.setText(dlg.selectedFiles()[0]) self._save_session() @staticmethod diff --git a/ameba_control_panel/managers/log_manager.py b/ameba_control_panel/managers/log_manager.py index 8203f42..82de855 100644 --- a/ameba_control_panel/managers/log_manager.py +++ b/ameba_control_panel/managers/log_manager.py @@ -1,5 +1,6 @@ from __future__ import annotations +import sys from collections import deque from pathlib import Path from typing import Callable, Deque, List, Optional, Tuple, TYPE_CHECKING @@ -103,7 +104,13 @@ class LogManager(QObject): self.view.log_view.set_matches([], -1) def save(self) -> None: - path, _ = QFileDialog.getSaveFileName(self.view, "Save Log", str(Path.home() / "ameba_log.txt")) + dlg = QFileDialog(self.view, "Save Log", str(Path.home() / "ameba_log.txt")) + dlg.setAcceptMode(QFileDialog.AcceptMode.AcceptSave) + if sys.platform == "linux": + dlg.setOption(QFileDialog.Option.DontUseNativeDialog, True) + if dlg.exec() != QFileDialog.DialogCode.Accepted or not dlg.selectedFiles(): + return + path = dlg.selectedFiles()[0] if not path: return try: diff --git a/script/auto_run.py b/script/auto_run.py index 0624a14..7448329 100644 --- a/script/auto_run.py +++ b/script/auto_run.py @@ -13,7 +13,11 @@ def _bootstrap_path() -> None: def _setup_linux_platform() -> None: """Set Qt platform plugin for Linux X11/Wayland compatibility.""" - if sys.platform != "linux" or os.environ.get("QT_QPA_PLATFORM"): + if sys.platform != "linux": + return + os.environ.setdefault("QT_DISABLE_XDG_DESKTOP_PORTAL", "1") + os.environ.setdefault("GIO_USE_VOLUME_MONITOR", "unix") + if os.environ.get("QT_QPA_PLATFORM"): return if os.environ.get("WAYLAND_DISPLAY"): os.environ["QT_QPA_PLATFORM"] = "wayland;xcb"