From fca4f9e359c589ea0e0f00e1232c91527ccb8233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elberte=20Pl=C3=ADnio?= Date: Fri, 17 Jul 2026 11:27:21 -0300 Subject: [PATCH] feat(desktop-linux): prefer maim for screenshots and silence import - add maim as the preferred screenshot tool (silent, reliable under Xvfb/Xwayland) - pass -silent to the ImageMagick import fallback so it never rings the X bell - update builder tests --- packages/desktop-linux/src/screenshot.ts | 17 ++++++++++++++--- packages/desktop-linux/test/builders.test.ts | 12 +++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/desktop-linux/src/screenshot.ts b/packages/desktop-linux/src/screenshot.ts index c5706be..61a4ba6 100644 --- a/packages/desktop-linux/src/screenshot.ts +++ b/packages/desktop-linux/src/screenshot.ts @@ -8,7 +8,7 @@ import { findOnPath } from "./util.js"; const SCREENSHOT_TIMEOUT_MS = 20_000; const PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); -export type ScreenshotTool = "import" | "xwd" | "scrot"; +export type ScreenshotTool = "maim" | "import" | "xwd" | "scrot"; export interface ScreenshotStep { cmd: string; @@ -31,6 +31,9 @@ export interface ScreenshotResult { export function detectScreenshotTool( env: EnvLike = process.env, ): ScreenshotTool | null { + if (findOnPath("maim", env) !== null) { + return "maim"; + } if (findOnPath("import", env) !== null) { return "import"; } @@ -51,11 +54,19 @@ export function buildScreenshotCommand( ): ScreenshotStep[] { parseDisplayNumber(display); switch (tool) { + case "maim": + return [ + { + cmd: "maim", + args: [outPath], + requiresDisplayEnv: true, + }, + ]; case "import": return [ { cmd: "import", - args: ["-display", display, "-window", "root", outPath], + args: ["-silent", "-display", display, "-window", "root", outPath], }, ]; case "xwd": { @@ -119,7 +130,7 @@ export async function screenshot( if (tool === null) { throw new Error( "No screenshot tool found on PATH. Install one of: " + - "imagemagick (provides `import` and `convert`), " + + "maim (preferred), imagemagick (provides `import` and `convert`), " + "xorg-xwd (`xwd`, combined with imagemagick `convert`), or scrot.", ); } diff --git a/packages/desktop-linux/test/builders.test.ts b/packages/desktop-linux/test/builders.test.ts index 5465d26..3f8bf95 100644 --- a/packages/desktop-linux/test/builders.test.ts +++ b/packages/desktop-linux/test/builders.test.ts @@ -102,11 +102,21 @@ describe("buildVncArgs", () => { }); describe("buildScreenshotCommand", () => { + it("builds the maim command, which targets the display via the DISPLAY env", () => { + expect(buildScreenshotCommand("maim", ":92", "/tmp/out.png")).toEqual([ + { + cmd: "maim", + args: ["/tmp/out.png"], + requiresDisplayEnv: true, + }, + ]); + }); + it("builds the import command", () => { expect(buildScreenshotCommand("import", ":92", "/tmp/out.png")).toEqual([ { cmd: "import", - args: ["-display", ":92", "-window", "root", "/tmp/out.png"], + args: ["-silent", "-display", ":92", "-window", "root", "/tmp/out.png"], }, ]); });