diff --git a/electron/ipc/channels.ts b/electron/ipc/channels.ts index 82cf105a..a656462d 100644 --- a/electron/ipc/channels.ts +++ b/electron/ipc/channels.ts @@ -102,6 +102,9 @@ export enum IPC { OpenPath = 'open_path', ReadFileText = 'read_file_text', + // Clipboard + SaveClipboardImage = 'save_clipboard_image', + // Notifications ShowNotification = 'show_notification', NotificationClicked = 'notification_clicked', diff --git a/electron/ipc/register.ts b/electron/ipc/register.ts index 30ddd569..5e2c6891 100644 --- a/electron/ipc/register.ts +++ b/electron/ipc/register.ts @@ -1,5 +1,6 @@ -import { ipcMain, dialog, shell, app, BrowserWindow, Notification } from 'electron'; +import { ipcMain, dialog, shell, app, clipboard, BrowserWindow, Notification } from 'electron'; import fs from 'fs'; +import os from 'os'; import { fileURLToPath } from 'url'; import { IPC } from './channels.js'; import { @@ -463,6 +464,20 @@ export function registerAllHandlers(win: BrowserWindow): void { return fs.readFileSync(args.filePath, 'utf8'); }); + // --- Clipboard --- + const clipboardImagePath = path.join(os.tmpdir(), 'parallel-code-clipboard.png'); + ipcMain.handle(IPC.SaveClipboardImage, async () => { + try { + const img = clipboard.readImage(); + if (img.isEmpty()) return null; + const buf = img.toPNG(); + await fs.promises.writeFile(clipboardImagePath, buf); + return clipboardImagePath; + } catch { + return null; + } + }); + // --- System --- ipcMain.handle(IPC.GetSystemFonts, () => getSystemMonospaceFonts()); diff --git a/electron/preload.cjs b/electron/preload.cjs index 7027ddb6..0abbb51f 100644 --- a/electron/preload.cjs +++ b/electron/preload.cjs @@ -93,6 +93,8 @@ const ALLOWED_CHANNELS = new Set([ // File links 'open_path', 'read_file_text', + // Clipboard + 'save_clipboard_image', // Notifications 'show_notification', 'notification_clicked', diff --git a/src/components/TerminalView.tsx b/src/components/TerminalView.tsx index 7252801b..6e66fb33 100644 --- a/src/components/TerminalView.tsx +++ b/src/components/TerminalView.tsx @@ -191,9 +191,16 @@ export function TerminalView(props: TerminalViewProps) { if (isPaste) { e.preventDefault(); - navigator.clipboard.readText().then((text) => { - if (text) enqueueInput(text); - }); + (async () => { + const text = await navigator.clipboard.readText().catch(() => ''); + if (text) { + enqueueInput(text); + return; + } + // Fall back to clipboard image → save to temp file and paste path + const filePath = await invoke(IPC.SaveClipboardImage); + if (filePath) enqueueInput(filePath); + })().catch(() => {}); return false; }