Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion native/opennow-streamer/src/gstreamer_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::gstreamer_liveness::{
};
use crate::gstreamer_platform::{
apply_render_surface_to_video_sink, primary_display_refresh_hz,
start_external_renderer_window_guard,
start_external_renderer_window_guard, update_external_renderer_surface,
};
use crate::gstreamer_transitions::DEFAULT_VIDEO_QUEUE_DEPTH;
use crate::protocol::{
Expand Down Expand Up @@ -276,6 +276,9 @@ impl GstreamerRenderState {
};

if use_external_renderer_window() {
if let Some(surface) = self.surface.lock().ok().and_then(|surface| surface.clone()) {
update_external_renderer_surface(&surface);
}
if !self
.external_window_guard_started
.swap(true, Ordering::SeqCst)
Expand Down
124 changes: 107 additions & 17 deletions native/opennow-streamer/src/gstreamer_platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub(crate) fn start_external_renderer_window_guard(
) {
thread::spawn(move || {
let mut logged = false;
for _ in 0..200 {
while !stop.load(Ordering::SeqCst) {
if stop.load(Ordering::SeqCst) {
break;
}
Expand Down Expand Up @@ -105,8 +105,7 @@ pub(crate) fn set_native_shortcut_bindings(bindings: &NativeStreamerShortcutBind
}

#[cfg(not(target_os = "windows"))]
pub(crate) fn set_native_shortcut_bindings(_bindings: &NativeStreamerShortcutBindings) {
}
pub(crate) fn set_native_shortcut_bindings(_bindings: &NativeStreamerShortcutBindings) {}

#[cfg(target_os = "windows")]
pub(crate) fn clear_native_shortcut_bindings() {
Expand All @@ -116,12 +115,34 @@ pub(crate) fn clear_native_shortcut_bindings() {
}

#[cfg(not(target_os = "windows"))]
pub(crate) fn clear_native_shortcut_bindings() {
pub(crate) fn clear_native_shortcut_bindings() {}

#[cfg(target_os = "windows")]
pub(crate) fn update_external_renderer_surface(surface: &NativeRenderSurface) {
let target = surface
.window_handle
.as_deref()
.and_then(|window_handle| parse_window_handle(window_handle).ok())
.and_then(|window_handle| {
surface
.visible
.then_some(())
.and(surface.rect.as_ref())
.map(|rect| (window_handle, normalized_render_rect(Some(rect))))
});

unsafe {
win32_renderer_window::set_render_target_surface(target);
}
}

#[cfg(not(target_os = "windows"))]
pub(crate) fn update_external_renderer_surface(_surface: &NativeRenderSurface) {}

#[cfg(target_os = "windows")]
pub(crate) mod win32_renderer_window {
use crate::gstreamer_input::NativeWindowInputEvent;
use crate::protocol::NativeRenderRect;
use crate::protocol::{NativeStreamerShortcutAction, NativeStreamerShortcutBindings};
use crate::shortcuts::NativeShortcutMatcher;
use std::collections::{HashMap, HashSet};
Expand Down Expand Up @@ -235,6 +256,12 @@ pub(crate) mod win32_renderer_window {
area: i64,
}

#[derive(Clone, Copy)]
struct RenderTargetSurface {
hwnd: isize,
client_rect: Rect,
}

#[repr(C)]
#[derive(Clone, Copy)]
struct Rect {
Expand All @@ -244,6 +271,13 @@ pub(crate) mod win32_renderer_window {
bottom: i32,
}

#[repr(C)]
#[derive(Clone, Copy)]
struct Point {
x: i32,
y: i32,
}

#[repr(C)]
struct MonitorInfo {
cb_size: Dword,
Expand Down Expand Up @@ -315,6 +349,7 @@ pub(crate) mod win32_renderer_window {
static ESCAPE_HOLD_TOKEN: OnceLock<AtomicU64> = OnceLock::new();
static ESCAPE_KEY_PRESS: OnceLock<Mutex<Option<EscapeKeyPress>>> = OnceLock::new();
static SHORTCUT_MATCHER: OnceLock<Mutex<NativeShortcutMatcher>> = OnceLock::new();
static RENDER_TARGET_SURFACE: OnceLock<Mutex<Option<RenderTargetSurface>>> = OnceLock::new();

#[link(name = "user32")]
unsafe extern "system" {
Expand All @@ -325,6 +360,7 @@ pub(crate) mod win32_renderer_window {
wparam: Wparam,
lparam: Lparam,
) -> Lresult;
fn ClientToScreen(hwnd: Hwnd, point: *mut Point) -> Bool;
fn ClipCursor(rect: *const Rect) -> Bool;
fn DefWindowProcW(hwnd: Hwnd, message: Uint, wparam: Wparam, lparam: Lparam) -> Lresult;
fn EnumWindows(
Expand Down Expand Up @@ -372,6 +408,22 @@ pub(crate) mod win32_renderer_window {
fn GetCurrentProcessId() -> u32;
}

pub unsafe fn set_render_target_surface(target: Option<(usize, NativeRenderRect)>) {
let target_surface = target.map(|(window_handle, rect)| RenderTargetSurface {
hwnd: window_handle as isize,
client_rect: Rect {
left: rect.x,
top: rect.y,
right: rect.x.saturating_add(rect.width.max(2)),
bottom: rect.y.saturating_add(rect.height.max(2)),
},
});
let slot = RENDER_TARGET_SURFACE.get_or_init(|| Mutex::new(None));
if let Ok(mut current) = slot.lock() {
*current = target_surface;
}
}

pub unsafe fn set_input_event_sender(sender: Option<Sender<NativeWindowInputEvent>>) {
let slot = INPUT_EVENT_SENDER.get_or_init(|| Mutex::new(None));
if let Ok(mut current) = slot.lock() {
Expand Down Expand Up @@ -496,7 +548,7 @@ pub(crate) mod win32_renderer_window {
configured = true;
}

if let Some(rect) = monitor_rect_for_window(hwnd) {
if let Some(rect) = target_renderer_rect().or_else(|| monitor_rect_for_window(hwnd)) {
SetWindowPos(
hwnd,
HWND_NOTOPMOST,
Expand All @@ -522,6 +574,28 @@ pub(crate) mod win32_renderer_window {
configured
}

unsafe fn render_rect_to_screen_rect(hwnd: Hwnd, rect: Rect) -> Option<Rect> {
if hwnd.is_null() {
return None;
}
let mut origin = Point {
x: rect.left,
y: rect.top,
};
if ClientToScreen(hwnd, &mut origin) == 0 {
return None;
}
let width = rect.right.saturating_sub(rect.left).max(2);
let height = rect.bottom.saturating_sub(rect.top).max(2);

Some(Rect {
left: origin.x,
top: origin.y,
right: origin.x.saturating_add(width),
bottom: origin.y.saturating_add(height),
})
}

unsafe fn install_input_wndproc(hwnd: Hwnd) -> bool {
let key = hwnd as isize;
let map = ORIGINAL_WNDPROCS.get_or_init(|| Mutex::new(HashMap::new()));
Expand Down Expand Up @@ -561,8 +635,8 @@ pub(crate) mod win32_renderer_window {
handle_raw_input(lparam as Hrawinput);
return 0;
}
let handled_legacy_shortcut =
is_keyboard_message(message) && handle_legacy_shortcut_keyboard(message, wparam, lparam);
let handled_legacy_shortcut = is_keyboard_message(message)
&& handle_legacy_shortcut_keyboard(message, wparam, lparam);
if handled_legacy_shortcut {
return 0;
}
Expand Down Expand Up @@ -628,12 +702,21 @@ pub(crate) mod win32_renderer_window {
Some(info.rc_monitor)
}

unsafe fn target_renderer_rect() -> Option<Rect> {
let target = RENDER_TARGET_SURFACE
.get()
.and_then(|surface| surface.lock().ok().and_then(|surface| *surface))?;
let hwnd = target.hwnd as Hwnd;
render_rect_to_screen_rect(hwnd, target.client_rect)
.or_else(|| monitor_rect_for_window(hwnd))
}

unsafe fn begin_input_capture(hwnd: Hwnd) {
SetForegroundWindow(hwnd);
SetFocus(hwnd);
SetCapture(hwnd);
register_raw_input_devices(hwnd);
if let Some(rect) = monitor_rect_for_window(hwnd) {
if let Some(rect) = target_renderer_rect().or_else(|| monitor_rect_for_window(hwnd)) {
ClipCursor(&rect);
}
hide_cursor();
Expand Down Expand Up @@ -989,20 +1072,26 @@ pub(crate) mod win32_renderer_window {
}
let modifiers = current_modifier_flags(&keys);
if let Some(action) = shortcut_action_for_keypress(keycode, scancode, modifiers) {
keys.insert(scancode, PressedKey {
keycode,
keys.insert(
scancode,
suppressed: true,
});
PressedKey {
keycode,
scancode,
suppressed: true,
},
);
drop(keys);
handle_shortcut_action(action);
return;
}
keys.insert(scancode, PressedKey {
keycode,
keys.insert(
scancode,
suppressed: false,
});
PressedKey {
keycode,
scancode,
suppressed: false,
},
);
} else {
let Some(previous) = keys.remove(&scancode) else {
return;
Expand Down Expand Up @@ -1250,7 +1339,8 @@ pub(crate) mod win32_renderer_window {
fn shortcut_action_releases_input_capture(action: NativeStreamerShortcutAction) -> bool {
matches!(
action,
NativeStreamerShortcutAction::ToggleFullscreen | NativeStreamerShortcutAction::StopStream
NativeStreamerShortcutAction::ToggleFullscreen
| NativeStreamerShortcutAction::StopStream
)
}

Expand Down
26 changes: 13 additions & 13 deletions opennow-stable/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading