summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2026-07-24 12:32:00 +0200
committerYuval Adam <_@yuv.al>2026-07-24 12:32:00 +0200
commit8e64e5eef0173b3f7586404650151acc684e57d7 (patch)
treee99ddec68a0b9f43ec685e5be7573cbd8c5dd35c /src
parent0747fd8318a092778d420eeee55851cf49ee8aec (diff)
Use XWayland clipboard bridge for reliable copying
Diffstat (limited to 'src')
-rw-r--r--src/parley/desktop.py35
1 files changed, 18 insertions, 17 deletions
diff --git a/src/parley/desktop.py b/src/parley/desktop.py
index 4072655..37f8a7f 100644
--- a/src/parley/desktop.py
+++ b/src/parley/desktop.py
@@ -12,24 +12,25 @@ class DesktopIntegrationError(ParleyError):
def copy_text(text: str) -> None:
- """Copy text with GDK, retaining ownership in the long-running daemon."""
+ """Copy text through XWayland's clipboard bridge on GNOME."""
+ executable = shutil.which("xclip")
+ if executable is None:
+ raise DesktopIntegrationError(
+ "xclip is not installed; transcript was saved but not copied"
+ )
try:
- import gi
-
- gi.require_version("Gdk", "4.0")
- gi.require_version("Gtk", "4.0")
- from gi.repository import Gdk, Gtk
-
- # GDK 4 treats opening a display before GTK initialization as fatal.
- Gtk.init()
- display = Gdk.Display.get_default()
- if display is None:
- raise DesktopIntegrationError("could not connect to the graphical display")
- display.get_clipboard().set(text)
- except DesktopIntegrationError:
- raise
- except Exception as error:
- raise DesktopIntegrationError(f"GDK clipboard is unavailable: {error}") from error
+ result = subprocess.run(
+ [executable, "-selection", "clipboard", "-in"],
+ input=text,
+ text=True,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ timeout=10,
+ )
+ except (OSError, subprocess.TimeoutExpired) as error:
+ raise DesktopIntegrationError(f"could not copy transcript: {error}") from error
+ if result.returncode != 0:
+ raise DesktopIntegrationError("xclip could not access the clipboard")
def notify(summary: str, body: str) -> None: