diff --git a/scratch/pw.rs b/scratch/pw.rs
deleted file mode 100644
index be1a30f..0000000
--- a/scratch/pw.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-use pipewire as pw;
-fn main() {}
diff --git a/scratch/wl.patch b/scratch/wl.patch
deleted file mode 100644
index 70539d8..0000000
--- a/scratch/wl.patch
+++ /dev/null
@@ -1,30 +0,0 @@
---- src/capture/wayland.rs
-+++ src/capture/wayland.rs
-@@ -4,8 +4,7 @@
- use ashpd::desktop::screencast::{Screencast, CursorMode, PersistMode, SourceType};
- use std::os::unix::io::RawFd;
-
- pub struct WaylandCapture {
-- fd: RawFd,
-- node_id: u32,
-+ stream: crate::capture::wayland_stream::PipeWireStream,
- }
-
-@@ -37,13 +36,13 @@
- node_id = stream.node_id();
- }
-
-- Ok(Self { fd, node_id })
-+ let stream = crate::capture::wayland_stream::PipeWireStream::new(node_id, fd)?;
-+ Ok(Self { stream })
- }
- }
-
- impl FrameSource for WaylandCapture {
- fn next_frame(&mut self) -> Result> {
-- // Wait, Wayland capture requires a pipewire stream running in a background thread to yield buffers.
-- // For Phase 1, we are mocking this out until Phase 2 is built.
-- Ok(Frame::DmaBuf { width: 1920, height: 1080, format: 0, fd: self.fd, stride: 0, offset: 0 })
-+ self.stream.receiver.recv().map_err(|e| Box::new(e) as Box)
- }
- }
diff --git a/scratch/wl2.patch b/scratch/wl2.patch
deleted file mode 100644
index ed17351..0000000
--- a/scratch/wl2.patch
+++ /dev/null
@@ -1,30 +0,0 @@
---- src/capture/wayland.rs
-+++ src/capture/wayland.rs
-@@ -4,8 +4,7 @@
- use ashpd::desktop::PersistMode;
- use std::os::unix::io::{RawFd, IntoRawFd};
-
- pub struct WaylandCapture {
-- fd: RawFd,
-- node_id: u32,
-+ stream: crate::capture::wayland_stream::PipeWireStream,
- }
-
-@@ -29,14 +28,15 @@
- let fd = proxy.open_pipe_wire_remote(&session, Default::default()).await?;
-
-- Ok(Self {
-- fd: fd.into_raw_fd(),
-- node_id,
-- })
-+ let stream = crate::capture::wayland_stream::PipeWireStream::new(node_id, fd.into_raw_fd())?;
-+ Ok(Self { stream })
- }
- }
-
- impl FrameSource for WaylandCapture {
- fn next_frame(&mut self) -> Result> {
-- Err("Wayland/Pipewire frame extraction not fully implemented yet".into())
-+ self.stream.next_frame().map_err(|e| Box::new(e) as Box)
- }
- }
diff --git a/src/bin/vrec-ui.rs b/src/bin/vrec-ui.rs
index de1928b..dbdca63 100644
--- a/src/bin/vrec-ui.rs
+++ b/src/bin/vrec-ui.rs
@@ -53,6 +53,10 @@ fn main() -> Result<(), Box> {
println!("Hotkey triggered! Sending SaveReplay command to daemon...");
if let Err(e) = send_command(Command::SaveReplay) {
eprintln!("Failed to communicate with daemon: {}", e);
+ } else {
+ if env::var("XDG_SESSION_TYPE").unwrap_or_else(|_| "x11".to_string()).to_lowercase() != "wayland" {
+ vrec::overlay::show_saved_overlay();
+ }
}
}
}
diff --git a/src/bin/vrec-ui.rs.orig b/src/bin/vrec-ui.rs.orig
new file mode 100644
index 0000000..de1928b
--- /dev/null
+++ b/src/bin/vrec-ui.rs.orig
@@ -0,0 +1,61 @@
+use vrec::ipc::Command;
+use std::os::unix::net::UnixStream;
+use std::io::Write;
+use std::env;
+use global_hotkey::{GlobalHotKeyManager, hotkey::{HotKey, Modifiers, Code}, GlobalHotKeyEvent};
+
+fn send_command(cmd: Command) -> Result<(), Box> {
+ let socket_path = format!("{}/vrec.sock", env::var("XDG_RUNTIME_DIR").unwrap_or_else(|_| "/tmp".to_string()));
+ let mut stream = UnixStream::connect(&socket_path)?;
+ let payload = serde_json::to_vec(&cmd)?;
+ let len_buf = (payload.len() as u32).to_le_bytes();
+ stream.write_all(&len_buf)?;
+ stream.write_all(&payload)?;
+ Ok(())
+}
+
+fn main() -> Result<(), Box> {
+ println!("Starting vrec UI/Hotkey process...");
+
+ // Check session type
+ let session_type = env::var("XDG_SESSION_TYPE").unwrap_or_else(|_| "x11".to_string());
+ let desktop = env::var("XDG_CURRENT_DESKTOP").unwrap_or_else(|_| "".to_string()).to_lowercase();
+
+ let is_gnome = desktop.contains("gnome") || desktop.contains("ubuntu");
+ let is_kde = desktop.contains("kde");
+
+ if session_type.to_lowercase() == "wayland" {
+ if is_gnome || is_kde {
+ println!("WARNING: wlr-layer-shell unsupported on GNOME/KDE Wayland. Degrading to hotkey-only mode.");
+ println!("Note: Global hotkeys may also fail to register on some Wayland compositors.");
+ } else {
+ println!("wlroots-based compositor detected. (wlr-layer-shell overlay would be spawned here).");
+ }
+ } else {
+ println!("X11 session detected. (X11 override-redirect overlay would be spawned here).");
+ }
+
+ let manager = GlobalHotKeyManager::new()?;
+ let hotkey = HotKey::new(Some(Modifiers::CONTROL | Modifiers::SHIFT), Code::KeyR);
+
+ if let Err(e) = manager.register(hotkey) {
+ eprintln!("Failed to register global hotkey! Wayland compositor might be blocking it: {}", e);
+ eprintln!("Fallback: running without global hotkey. Send commands via socket manually.");
+ } else {
+ println!("Registered global hotkey Ctrl+Shift+R to trigger replay save.");
+ }
+
+ let receiver = GlobalHotKeyEvent::receiver();
+ loop {
+ if let Ok(event) = receiver.recv() {
+ if event.id == hotkey.id() {
+ if event.state == global_hotkey::HotKeyState::Pressed {
+ println!("Hotkey triggered! Sending SaveReplay command to daemon...");
+ if let Err(e) = send_command(Command::SaveReplay) {
+ eprintln!("Failed to communicate with daemon: {}", e);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/overlay.rs b/src/overlay.rs
index e69de29..cf73a12 100644
--- a/src/overlay.rs
+++ b/src/overlay.rs
@@ -0,0 +1,45 @@
+use minifb::{Window, WindowOptions};
+use std::time::Duration;
+
+pub fn show_saved_overlay() {
+ let width = 300;
+ let height = 100;
+
+ let mut window = match Window::new(
+ "VRec Overlay",
+ width,
+ height,
+ WindowOptions {
+ borderless: true,
+ title: false,
+ resize: false,
+ scale: minifb::Scale::X1,
+ scale_mode: minifb::ScaleMode::Stretch,
+ topmost: true,
+ transparency: true,
+ none: false,
+ }
+ ) {
+ Ok(win) => win,
+ Err(e) => {
+ eprintln!("Failed to create overlay window: {}", e);
+ return;
+ }
+ };
+
+ // Create a semi-transparent green box or just dark gray
+ let buffer: Vec = vec![0xFF222222; width * height];
+
+ window.set_target_fps(60);
+
+ let start_time = std::time::Instant::now();
+ let display_duration = Duration::from_secs(2);
+
+ while window.is_open() && start_time.elapsed() < display_duration {
+ // We could render text here, but for now we just show a flash/banner.
+ if let Err(e) = window.update_with_buffer(&buffer, width, height) {
+ eprintln!("Overlay update error: {}", e);
+ break;
+ }
+ }
+}