From 2790159d047630e797809b86e7d793ffdb8378cf Mon Sep 17 00:00:00 2001 From: Jean-Pierre Martineau Date: Mon, 7 Sep 2026 20:28:54 -0400 Subject: [PATCH] Ask for a window MeshTerm fits in, rather than taking whatever is open JP saw the PicoCalc's wordmark on a desktop session. The splash picks the widest mark that fits, the desktop one is 71 columns, and below that it swaps to the 53 drawn for the handheld -- so the app was announcing itself as the handheld and truncating every menu description onto the pager underneath. The window was 64 columns. reopen() passed no window argument, so wt.exe put the session in a *tab* of whatever window happened to be open and it inherited that size; with no window open it would instead have taken the reader's global launch size, which is a setting about their shell and nothing to do with this app. Either way the app could land somewhere too small for it, and the failure was quiet and cosmetic rather than anything that announced itself. It now asks for a window of its own at the platform's stated minimum plus a margin -- 80x30 on the desktop, derived from readable_cols/readable_rows so it follows them. Windows Terminal clamps to what the display can show, so a small screen degrades exactly as it did before. The tab is titled MeshTerm too. It was showing the executable's full path, which on a downloaded build is a line of Downloads folder. The icon is not ours to set -- Windows Terminal takes that from a profile and a bare command line is not one. Release 0.2.8. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 17 ++++++++++++++ README.md | 12 +++++----- meshterm/__init__.py | 2 +- meshterm/core/winterminal.py | 40 ++++++++++++++++++++++++++++++++- tests/test_winterminal.py | 43 ++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75833c1..fc056df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,23 @@ allowed to change behaviour, not just add to it. ## [Unreleased] +## [0.2.8] — 2026-09-07 + +### Fixed + +- **The window MeshTerm opened for itself was too small, and it showed.** The startup + wordmark is 71 columns wide; below that the splash quietly swaps to the narrow one drawn + for the PicoCalc — so a desktop session came up wearing the handheld's mark, with every + menu description truncated onto the pager underneath it. + + MeshTerm was opening a *tab* in whatever Windows Terminal window happened to be around, + inheriting its size (64 columns on the machine this was found on). It now asks for a + window of its own, sized from the platform's own minimum plus a margin. Windows Terminal + clamps that to what the display can show, so a small screen degrades exactly as before. + +- The tab it opens is titled **MeshTerm**, not the executable's full path — which on a + downloaded build was a line of Downloads folder. + ## [0.2.7] — 2026-09-07 ### Changed diff --git a/README.md b/README.md index afa48fc..00c9eae 100644 --- a/README.md +++ b/README.md @@ -68,14 +68,14 @@ if anything goes wrong at startup the window closes before you can read why. **Windows** — open Windows Terminal or PowerShell, `cd` to your downloads, then: ```powershell -.\meshterm-0.2.7-windows-x64.exe +.\meshterm-0.2.8-windows-x64.exe ``` **macOS and Linux** — open Terminal, `cd` to your downloads, then: ```bash -chmod +x meshterm-0.2.7-* -./meshterm-0.2.7-* +chmod +x meshterm-0.2.8-* +./meshterm-0.2.8-* ``` ### A word about terminals, on Windows @@ -113,7 +113,7 @@ becomes just `meshterm` from anywhere. > project. > > - **macOS**: *"cannot be opened because the developer cannot be verified"*. Clear it with -> `xattr -d com.apple.quarantine meshterm-0.2.7-*` and run it again. +> `xattr -d com.apple.quarantine meshterm-0.2.8-*` and run it again. > - **Windows**: *"Windows protected your PC"*. Click **More info → Run anyway**. > > Every release ships a `SHA256SUMS` file if you'd rather check the download first. @@ -123,10 +123,10 @@ becomes just `meshterm` from anywhere. > MeshTerm uses that same folder. Set `MESHTERM_HOME` to try one in isolation: > > ```bash -> MESHTERM_HOME=~/meshterm-test ./meshterm-0.2.7-* # macOS, Linux +> MESHTERM_HOME=~/meshterm-test ./meshterm-0.2.8-* # macOS, Linux > ``` > ```powershell -> $env:MESHTERM_HOME = "$HOME\meshterm-test"; .\meshterm-0.2.7-windows-x64.exe +> $env:MESHTERM_HOME = "$HOME\meshterm-test"; .\meshterm-0.2.8-windows-x64.exe > ``` > > Same variable if you run two radios and want them kept apart. diff --git a/meshterm/__init__.py b/meshterm/__init__.py index 14d0179..bc24961 100644 --- a/meshterm/__init__.py +++ b/meshterm/__init__.py @@ -5,7 +5,7 @@ Supports USB, Bluetooth and TCP companion connection. For Windows, macOS and Lin from datetime import datetime -__version__ = "0.2.7" +__version__ = "0.2.8" __author__ = "Jean-Pierre Martineau" #: The year MeshTerm was first published; the copyright span starts here. diff --git a/meshterm/core/winterminal.py b/meshterm/core/winterminal.py index 786b8a8..29ede89 100644 --- a/meshterm/core/winterminal.py +++ b/meshterm/core/winterminal.py @@ -119,10 +119,48 @@ def reopen() -> bool: # arrive intact). `-d` keeps the working directory, which relative paths given # on the command line depend on. subprocess.Popen( # noqa: S603 - the argv is ours, not the reader's - [terminal, "-d", os.getcwd(), "--", *own_command()], + [ + terminal, + "-w", + "new", + "--size", + _wanted_size(), + # Otherwise the tab is titled with the executable's full path, which on a + # downloaded build is a line of Downloads folder. The icon is not ours to + # set: Windows Terminal takes that from a profile, and a bare command line + # is not one, so it gets the generic console glyph. + "--title", + "MeshTerm", + "-d", + os.getcwd(), + "--", + *own_command(), + ], env=child_environment(), close_fds=True, ) return True except OSError: return False + + +def _wanted_size() -> str: + """The window to ask Windows Terminal for, as ``cols,rows``. + + Asked for, because a window MeshTerm opens should be one MeshTerm fits in. Without + ``-w new`` the session lands as a *tab* in whatever window happens to be open and + inherits its size; without ``--size`` a new window takes the reader's global launch + size, which is a setting about their shell and not about this app. Either way the app + can arrive in a window too small for it, and the failure is quiet and cosmetic: the + startup wordmark is 71 columns, so at 70 it silently swaps to the narrow one drawn for + the PicoCalc, and a short window truncates every description onto the pager. + + The numbers come from the platform's own stated minimum plus a margin, so they follow + it rather than repeating it. Windows Terminal clamps to what the display can show, so + this is a request and not a demand — on a small screen the app degrades exactly as it + would have anyway. + """ + from ..platforms import get_platform + + platform = get_platform() + return f"{platform.readable_cols + 8},{platform.readable_rows + 6}" diff --git a/tests/test_winterminal.py b/tests/test_winterminal.py index bdda937..77f2fe6 100644 --- a/tests/test_winterminal.py +++ b/tests/test_winterminal.py @@ -131,3 +131,46 @@ def test_the_loader_path_the_bootloader_replaced_is_put_back( assert environment["LD_LIBRARY_PATH"] == "/opt/mine/lib" assert "LD_LIBRARY_PATH_ORIG" not in environment assert "DYLD_LIBRARY_PATH" not in environment + + +def test_the_window_asked_for_fits_the_startup_wordmark() -> None: + """The size request exists because a too-small window fails quietly, not loudly. + + The startup wordmark is 71 columns; below that the splash silently swaps to the narrow + one drawn for the PicoCalc, which is how this was found — a desktop session showing the + handheld's mark. The request has to clear that, not merely the platform's minimum. + """ + from meshterm.platforms import REGULAR, set_platform + from meshterm.ui.logo import load_logo, logo_width + + set_platform(REGULAR) + cols, rows = (int(part) for part in winterminal._wanted_size().split(",")) + + assert logo_width(load_logo(cols)) == 71, "the window asked for would get the narrow mark" + assert cols >= REGULAR.readable_cols + assert rows >= REGULAR.readable_rows + + +def test_the_session_gets_its_own_window_at_that_size(monkeypatch: pytest.MonkeyPatch) -> None: + """Both halves matter, and each was a separate way to arrive somewhere too small. + + Without ``-w new`` the session lands as a tab in whatever window is already open and + inherits its size — measured at 64 columns on a real machine, which is why the wrong + mark appeared. Without ``--size`` a new window takes the reader's global launch size, + a setting about their shell rather than about this app. + """ + started: list[list[str]] = [] + monkeypatch.setattr(sys, "platform", "win32") + monkeypatch.delenv(winterminal.REOPENED_ENV, raising=False) + monkeypatch.setattr(winterminal.shutil, "which", lambda _: r"C:\wt.exe") + monkeypatch.setattr( + winterminal.subprocess, "Popen", lambda argv, **_: started.append(argv) or None + ) + + assert winterminal.reopen() is True + argv = started[0] + assert argv[:3] == [r"C:\wt.exe", "-w", "new"] + assert "--size" in argv + assert argv[argv.index("--size") + 1] == winterminal._wanted_size() + # `--` must still separate wt's options from MeshTerm's, or `--mock` becomes wt's. + assert "--" in argv and argv.index("--") > argv.index("--size")