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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,10 @@ a restart of the studio. One studio at a time can use it: a second one's
browser sources fail saying so. Each page renders in a process of its own, so
a page that crashes fails only its own source, with the reason, while the
stream carries on. A crash of the browser itself fails every browser source.
**Reload** in Sources restarts a page, failed or not. A page opens no other
windows (`window.open` and new-tab links do nothing), and its dropdown lists,
such as a `<select>`'s, are not drawn yet.
**Reload** in Sources restarts a page, failed or not. A page's dropdown
lists, such as a `<select>`'s, draw over it and take clicks under
**Interact**, but it opens no other windows (`window.open` and new-tab links
do nothing).

An overlay is a title, lower third, or other graphic written as HTML and CSS,
drawn by the studio itself (through [Blitz](https://github.com/DioxusLabs/blitz))
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ render-sw:
loader=$(nix build --inputs-from . --no-link --print-out-paths nixpkgs#vulkan-loader)
icd=("$mesa"/share/vulkan/icd.d/lvp_icd.*.json)
export LD_LIBRARY_PATH="$loader/lib" VK_DRIVER_FILES="${icd[0]}"
cargo nextest run --locked -p moq-scene --lib --run-ignored only -E 'test(/^compositor::tests::/)'
cargo nextest run --locked -p moq-scene --lib --run-ignored only -E 'test(/^compositor::tests::/) | test(/^browser::layers::tests::/)'
cargo nextest run --locked -p moq-studio --features openh264 --run-ignored only -E 'test(/^engine::tests::the_program_/) | test(=setup::tests::times_every_canvas)'
# CEF's browser process opens an X display even to paint offscreen.
xvfb=$(nix build --inputs-from . --no-link --print-out-paths nixpkgs#xvfb-run)
Expand Down
1 change: 0 additions & 1 deletion quest/m0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ repository.
- [Audio mixes](/quest/m0/mixes.md) - per-output mixes, meters, monitoring, and sync offsets
- [Audio filters](/quest/m0/audio-filters.md) - per-source noise suppression, gate, compressor, limiter, and plugins, configured from the studio
- [Browser sources on macOS and Windows](/quest/m0/browser-source.md) - the out-of-process CEF pages Linux has, with shared GPU textures on the other desktops
- [Browser source popups](/quest/m0/browser-popups.md) - dropdowns and other in-page popups draw and take input
- [Published independently](/quest/m0/publish-independently.md) - a source opts out of the program and publishes its own track for services that place it themselves
- [Web studio](/quest/m0/web.md) - the full studio in wasm on WebGPU and WebCodecs, served from this repository
- [Virtual camera](/quest/m0/vcam/README.md) - a canvas's program exposed as a system camera on Linux, Windows, and macOS
Expand Down
19 changes: 0 additions & 19 deletions quest/m0/browser-popups.md

This file was deleted.

45 changes: 38 additions & 7 deletions rs/moq-scene/src/browser/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::sync::{Arc, Mutex, mpsc};
use cef::*;

use super::outbox::Commands;
use super::protocol::{Channel, Command, Event, Format, Id, Open, Plane, Start, Texture};
use super::protocol::{Area, Channel, Command, Event, Format, Id, Layer, Open, Plane, Start, Texture};
use super::{Button, Input, Modifiers};

/// Run one of CEF's subprocesses (renderer, GPU, utility, zygote).
Expand Down Expand Up @@ -495,6 +495,25 @@ wrap_render_handler! {
}
}

// The studio draws a popup widget over the page, and CEF hands input
// over it to it, so the studio sends input as for the page alone.
fn on_popup_show(&self, _browser: Option<&mut Browser>, show: ::std::os::raw::c_int) {
if show == 0 {
self.page.shared.send(&Event::Popup(self.page.id, None), &[]);
}
}

fn on_popup_size(&self, _browser: Option<&mut Browser>, rect: Option<&Rect>) {
let Some(rect) = rect else { return };
let area = Area {
x: rect.x,
y: rect.y,
width: rect.width.max(0) as u32,
height: rect.height.max(0) as u32,
};
self.page.shared.send(&Event::Popup(self.page.id, Some(area)), &[]);
}

fn on_paint(
&self,
_browser: Option<&mut Browser>,
Expand All @@ -504,7 +523,8 @@ wrap_render_handler! {
width: ::std::os::raw::c_int,
height: ::std::os::raw::c_int,
) {
if type_ != PaintElementType::VIEW || buffer.is_null() || width <= 0 || height <= 0 {
let Some(layer) = layer(type_) else { return };
if buffer.is_null() || width <= 0 || height <= 0 {
return;
}
let len = width as usize * height as usize * 4;
Expand All @@ -513,6 +533,7 @@ wrap_render_handler! {
let data = unsafe { std::slice::from_raw_parts(buffer, len) }.to_vec();
let event = Event::Pixels {
page: self.page.id,
layer,
width: width as u32,
height: height as u32,
data,
Expand All @@ -527,10 +548,9 @@ wrap_render_handler! {
_dirty_rects: Option<&[Rect]>,
info: Option<&AcceleratedPaintInfo>,
) {
let Some(info) = info else { return };
if type_ != PaintElementType::VIEW {
let (Some(info), Some(layer)) = (info, layer(type_)) else {
return;
}
};
let format = match info.format {
ColorType::RGBA_8888 => Format::Rgba,
ColorType::BGRA_8888 => Format::Bgra,
Expand Down Expand Up @@ -558,11 +578,22 @@ wrap_render_handler! {
// SAFETY: CEF owns these descriptors and keeps them open for this
// call, which outlasts the send that duplicates them.
let fds: Vec<_> = planes.iter().map(|plane| unsafe { BorrowedFd::borrow_raw(plane.fd) }).collect();
self.page.shared.paint(&Event::Texture(self.page.id, texture), &fds);
self.page.shared.paint(&Event::Texture(self.page.id, layer, texture), &fds);
}
}
}

/// The layer CEF painted, if it is one the studio shows.
fn layer(type_: PaintElementType) -> Option<Layer> {
if type_ == PaintElementType::VIEW {
Some(Layer::View)
} else if type_ == PaintElementType::POPUP {
Some(Layer::Popup)
} else {
None
}
}

wrap_audio_handler! {
struct HelperAudio {
page: Arc<Paged>,
Expand Down Expand Up @@ -680,7 +711,7 @@ wrap_life_span_handler! {
}

impl LifeSpanHandler {
// A source shows one page, and nothing would show a popup, so
// A source shows one page, and nothing would show another window, so
// `window.open` and `target="_blank"` open nothing. That also keeps
// the studio's pages the only browsers, whose closing ends the helper.
fn on_before_popup(
Expand Down
Loading