diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b76170..2b9d1d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to RigDoctor are recorded here. Format follows (`MAJOR.MINOR.PATCH`, pre-1.0). `__version__` and `pyproject.toml` must match the git release tag (so the auto-updater, D18, can compare versions). +## [0.7.1] - 2026-05-21 +### Fixed +- Shared terminal: a guest who joined **after** the host enabled the terminal stayed read-only. + The host now re-sends the terminal state when a guest joins, so the terminal is available. +- Inventory page no longer jumps back to the top when it refreshes (e.g. when elevated data + arrives) — scroll position is preserved and unchanged data isn't re-rendered. +- Shared terminal now follows the cursor to the bottom as output arrives (e.g. `ls -la`), + instead of staying scrolled up. + ## [0.7.0] - 2026-05-21 ### Added - **Shared terminal (M12, Tier 3)**: when the host enables it, the session shares a real **PTY** diff --git a/pyproject.toml b/pyproject.toml index 22419d0..fe0a1bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "rigdoctor" -version = "0.7.0" +version = "0.7.1" description = "Modular hardware monitoring & crash diagnostics for Linux gamers." readme = "README.md" requires-python = ">=3.11" diff --git a/src/rigdoctor/__init__.py b/src/rigdoctor/__init__.py index 6bc8e0b..345ec8c 100644 --- a/src/rigdoctor/__init__.py +++ b/src/rigdoctor/__init__.py @@ -1,3 +1,3 @@ """RigDoctor — modular hardware monitoring & crash diagnostics for Linux gamers.""" -__version__ = "0.7.0" +__version__ = "0.7.1" diff --git a/src/rigdoctor/gui/inventory_page.py b/src/rigdoctor/gui/inventory_page.py index 6e38e51..26c5c68 100644 --- a/src/rigdoctor/gui/inventory_page.py +++ b/src/rigdoctor/gui/inventory_page.py @@ -81,7 +81,7 @@ class InventoryPage(QWidget): header.addWidget(self._refresh_btn) root.addLayout(header) - scroll = QScrollArea() + self._scroll = scroll = QScrollArea() scroll.setWidgetResizable(True) scroll.setFrameShape(QFrame.Shape.NoFrame) scroll.setStyleSheet("background: transparent;") @@ -118,7 +118,11 @@ class InventoryPage(QWidget): if sections is None: # collection failed — keep current self._status.setText("collection failed") return + if sections == self._sections: # unchanged — don't rebuild (would jump scroll) + self._status.setText("") + return + scroll_pos = self._scroll.verticalScrollBar().value() self._sections = sections while self._list.count(): item = self._list.takeAt(0) @@ -129,6 +133,8 @@ class InventoryPage(QWidget): self._list.addWidget(_section_card(section)) self._list.addStretch(1) self._status.setText("") + # restore scroll after the layout settles so re-renders don't yank to the top + QTimer.singleShot(0, lambda: self._scroll.verticalScrollBar().setValue(scroll_pos)) def _copy(self) -> None: if self._sections: diff --git a/src/rigdoctor/gui/share_page.py b/src/rigdoctor/gui/share_page.py index 5c76a67..de456f9 100644 --- a/src/rigdoctor/gui/share_page.py +++ b/src/rigdoctor/gui/share_page.py @@ -147,7 +147,10 @@ class SharePage(QWidget): return kind = data.get("type") # frames forwarded from a guest if kind == "req_full": + # A guest just joined — send a full frame AND the current terminal state, so a + # guest that joins *after* the host enabled the terminal still gets access. self._host_ws.sendTextMessage(share.host_full_frame(self._sampler)) + self._send_terminal_state() elif kind == "pty_in" and self._pty: self._pty.write(base64.b64decode(data["data"])) elif kind == "pty_resize" and self._pty: diff --git a/src/rigdoctor/gui/terminal_widget.py b/src/rigdoctor/gui/terminal_widget.py index 72e5d92..6242d27 100644 --- a/src/rigdoctor/gui/terminal_widget.py +++ b/src/rigdoctor/gui/terminal_widget.py @@ -9,7 +9,7 @@ from __future__ import annotations import pyte from PySide6.QtCore import Qt, Signal -from PySide6.QtGui import QFontDatabase, QFontMetrics +from PySide6.QtGui import QFontDatabase, QFontMetrics, QTextCursor from PySide6.QtWidgets import QPlainTextEdit @@ -39,9 +39,13 @@ class TerminalView(QPlainTextEdit): self._render() def _render(self) -> None: - bar = self.verticalScrollBar().value() self.setPlainText("\n".join(self._screen.display)) - self.verticalScrollBar().setValue(bar) + # Follow the terminal cursor so output (e.g. `ls -la`) stays in view. + cursor = self.textCursor() + cursor.movePosition(QTextCursor.MoveOperation.Start) + cursor.movePosition(QTextCursor.MoveOperation.Down, QTextCursor.MoveMode.MoveAnchor, self._screen.cursor.y) + self.setTextCursor(cursor) + self.ensureCursorVisible() def resizeEvent(self, event): # noqa: N802 (Qt override) super().resizeEvent(event)