From 4a6fb7f5b2709a5240d1572ad5aeed8c55cba22c Mon Sep 17 00:00:00 2001 From: rope Date: Mon, 12 Oct 2026 20:37:32 +0100 Subject: [PATCH] Vesktop: open share dialog instantly, JPEG preview fills in Co-Authored-By: Claude Opus 5.5 --- hosts/FredOS-Gaming.nix | 7 +- patches/vesktop-pick-another-window.patch | 131 ------------- patches/vesktop-wayland-share-dialog.patch | 210 +++++++++++++++++++++ 3 files changed, 214 insertions(+), 134 deletions(-) delete mode 100644 patches/vesktop-pick-another-window.patch create mode 100644 patches/vesktop-wayland-share-dialog.patch diff --git a/hosts/FredOS-Gaming.nix b/hosts/FredOS-Gaming.nix index 8c71b2c..c2a5aeb 100644 --- a/hosts/FredOS-Gaming.nix +++ b/hosts/FredOS-Gaming.nix @@ -8,12 +8,13 @@ spotify # Preselect the last stream's audio source (e.g. Hearthstone) when it's # running again, instead of resetting to "None" every Go Live. - # "Pick Another Window" in the stream dialog or shift-clicking share - # bypasses the game auto-pick (see xdph.conf in settings/hyprland.nix). + # The Wayland dialog opens instantly with the preview filling in, and + # "Pick Another Window" or shift-clicking share bypasses the game + # auto-pick (see xdph.conf in settings/hyprland.nix). (vesktop.overrideAttrs (old: { patches = (old.patches or [ ]) ++ [ ../patches/vesktop-remember-stream-audio.patch - ../patches/vesktop-pick-another-window.patch + ../patches/vesktop-wayland-share-dialog.patch ]; })) lsfg-vk diff --git a/patches/vesktop-pick-another-window.patch b/patches/vesktop-pick-another-window.patch deleted file mode 100644 index 639b753..0000000 --- a/patches/vesktop-pick-another-window.patch +++ /dev/null @@ -1,131 +0,0 @@ ---- a/src/main/screenShare.ts -+++ b/src/main/screenShare.ts -@@ -4,7 +4,9 @@ - * SPDX-License-Identifier: GPL-3.0-or-later - */ - --import { desktopCapturer, session, Streams } from "electron"; -+import { app, desktopCapturer, session, Streams } from "electron"; -+import { writeFileSync } from "fs"; -+import { join } from "path"; - import type { StreamPick } from "renderer/components/ScreenSharePicker"; - import { IpcCommands, IpcEvents } from "shared/IpcEvents"; - -@@ -14,7 +16,31 @@ - const isWayland = - process.platform === "linux" && (process.env.XDG_SESSION_TYPE === "wayland" || !!process.env.WAYLAND_DISPLAY); - -+// renderer's PICK_ANOTHER ("Pick Another Window" in the stream dialog) -+const PICK_ANOTHER = "vesktop-pick-another"; -+ -+// FredOS: the XDPH custom picker (settings/hyprland.nix) auto-picks a running -+// game unless this file holds a fresh timestamp, then shows the full picker. -+function forceFullPicker() { -+ try { -+ writeFileSync( -+ join(process.env.XDG_RUNTIME_DIR ?? "/tmp", "xdph-pick-manually"), -+ String(Math.floor(Date.now() / 1000)) -+ ); -+ } catch {} -+} -+ -+// Shift held while clicking share = full picker -+let shiftDown = false; -+ - export function registerScreenShareHandler() { -+ app.on("browser-window-created", (_, win) => { -+ win.webContents.on("before-input-event", (_, input) => { -+ if (input.key === "Shift") shiftDown = input.type === "keyDown"; -+ }); -+ win.on("blur", () => (shiftDown = false)); -+ }); -+ - handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => { - const sources = await desktopCapturer.getSources({ - types: ["window", "screen"], -@@ -29,15 +55,19 @@ - session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => { - // request full resolution on wayland right away because we always only end up with one result anyway - const width = isWayland ? 1920 : 176; -- const sources = await desktopCapturer -- .getSources({ -- types: ["window", "screen"], -- thumbnailSize: { -- width, -- height: width * (9 / 16) -- } -- }) -- .catch(err => console.error("Error during screenshare picker", err)); -+ const getSources = () => -+ desktopCapturer -+ .getSources({ -+ types: ["window", "screen"], -+ thumbnailSize: { -+ width, -+ height: width * (9 / 16) -+ } -+ }) -+ .catch(err => console.error("Error during screenshare picker", err)); -+ -+ if (isWayland && shiftDown) forceFullPicker(); -+ let sources = await getSources(); - - if (!sources) return callback({}); - -@@ -48,14 +78,22 @@ - })); - - if (isWayland) { -- const video = data[0]; -- if (video) { -+ let video = data[0]; -+ while (video) { - const stream = await sendRendererCommand(IpcCommands.SCREEN_SHARE_PICKER, { - screens: [video], - skipPicker: true - }).catch(() => null); - - if (stream === null) return callback({}); -+ if (stream.id !== PICK_ANOTHER) break; -+ -+ // re-run the portal, this time with the full picker -+ forceFullPicker(); -+ sources = await getSources(); -+ if (!sources) return callback({}); -+ const [source] = sources; -+ video = source && { id: source.id, name: source.name, url: source.thumbnail.toDataURL() }; - } - - callback(video ? { video: sources[0] } : {}); ---- a/src/renderer/components/ScreenSharePicker.tsx -+++ b/src/renderer/components/ScreenSharePicker.tsx -@@ -82,6 +82,10 @@ - url: string; - } - -+// Returned instead of a source id when "Pick Another Window" is clicked; main -+// re-runs the portal with the full picker (keep in sync with main/screenShare.ts). -+export const PICK_ANOTHER = "vesktop-pick-another"; -+ - export let currentSettings: StreamSettings | null = null; - - const logger = new Logger("VesktopScreenShare"); -@@ -829,6 +833,18 @@ - Go Live - - -+ {skipPicker && ( -+ -+ )} -+ - {selected && !skipPicker ? ( - + ++ {skipPicker && ( ++ ++ )} ++ + {selected && !skipPicker ? ( +