desktop: Recreate Player for each movie, and don't start with a Player unless a movie has been specified
This commit is contained in:
parent
df51531de6
commit
e97d32dbc7
|
@ -6,7 +6,6 @@ use crate::util::{
|
||||||
get_screen_size, parse_url, pick_file, winit_key_to_char, winit_to_ruffle_key_code,
|
get_screen_size, parse_url, pick_file, winit_key_to_char, winit_to_ruffle_key_code,
|
||||||
winit_to_ruffle_text_control,
|
winit_to_ruffle_text_control,
|
||||||
};
|
};
|
||||||
use crate::{CALLSTACK, SWF_INFO};
|
|
||||||
use anyhow::{Context, Error};
|
use anyhow::{Context, Error};
|
||||||
use ruffle_core::{PlayerEvent, StageDisplayState};
|
use ruffle_core::{PlayerEvent, StageDisplayState};
|
||||||
use ruffle_render::backend::ViewportDimensions;
|
use ruffle_render::backend::ViewportDimensions;
|
||||||
|
@ -14,17 +13,15 @@ use ruffle_render_wgpu::backend::WgpuRenderBackend;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use url::Url;
|
|
||||||
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Size};
|
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Size};
|
||||||
use winit::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent};
|
use winit::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent};
|
||||||
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy};
|
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder};
|
||||||
use winit::window::{Fullscreen, Icon, Window, WindowBuilder};
|
use winit::window::{Fullscreen, Icon, Window, WindowBuilder};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
opt: Opt,
|
opt: Opt,
|
||||||
window: Rc<Window>,
|
window: Rc<Window>,
|
||||||
event_loop: Option<EventLoop<RuffleEvent>>,
|
event_loop: Option<EventLoop<RuffleEvent>>,
|
||||||
event_loop_proxy: EventLoopProxy<RuffleEvent>,
|
|
||||||
gui: Arc<Mutex<GuiController>>,
|
gui: Arc<Mutex<GuiController>>,
|
||||||
player: PlayerController,
|
player: PlayerController,
|
||||||
min_window_size: LogicalSize<u32>,
|
min_window_size: LogicalSize<u32>,
|
||||||
|
@ -65,61 +62,25 @@ impl App {
|
||||||
opt.power.into(),
|
opt.power.into(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let player = PlayerController::new(
|
let mut player = PlayerController::new(
|
||||||
&opt,
|
|
||||||
event_loop.create_proxy(),
|
event_loop.create_proxy(),
|
||||||
movie_url.clone(),
|
|
||||||
window.clone(),
|
window.clone(),
|
||||||
gui.descriptors().clone(),
|
gui.descriptors().clone(),
|
||||||
gui.create_movie_view(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut app = Self {
|
if let Some(movie_url) = movie_url {
|
||||||
|
player.create(&opt, movie_url, gui.create_movie_view());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
opt,
|
opt,
|
||||||
window,
|
window,
|
||||||
event_loop_proxy: event_loop.create_proxy(),
|
|
||||||
event_loop: Some(event_loop),
|
event_loop: Some(event_loop),
|
||||||
gui: Arc::new(Mutex::new(gui)),
|
gui: Arc::new(Mutex::new(gui)),
|
||||||
player,
|
player,
|
||||||
min_window_size,
|
min_window_size,
|
||||||
max_window_size,
|
max_window_size,
|
||||||
};
|
})
|
||||||
|
|
||||||
if let Some(movie_url) = movie_url {
|
|
||||||
app.load_swf(movie_url)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(app)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_swf(&mut self, url: Url) -> Result<(), Error> {
|
|
||||||
let filename = url
|
|
||||||
.path_segments()
|
|
||||||
.and_then(|segments| segments.last())
|
|
||||||
.unwrap_or_else(|| url.as_str());
|
|
||||||
let title = format!("Ruffle - {filename}");
|
|
||||||
self.window.set_title(&title);
|
|
||||||
SWF_INFO.with(|i| *i.borrow_mut() = Some(filename.to_string()));
|
|
||||||
|
|
||||||
let event_loop_proxy = self.event_loop_proxy.clone();
|
|
||||||
let on_metadata = move |swf_header: &ruffle_core::swf::HeaderExt| {
|
|
||||||
let _ = event_loop_proxy.send_event(RuffleEvent::OnMetadata(swf_header.clone()));
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut parameters: Vec<(String, String)> = url.query_pairs().into_owned().collect();
|
|
||||||
parameters.extend(self.opt.parameters());
|
|
||||||
|
|
||||||
if let Some(mut player) = self.player.get() {
|
|
||||||
CALLSTACK.with(|callstack| {
|
|
||||||
*callstack.borrow_mut() = Some(player.callstack());
|
|
||||||
});
|
|
||||||
|
|
||||||
player.fetch_root_movie(url.to_string(), parameters, Box::new(on_metadata));
|
|
||||||
} else {
|
|
||||||
unimplemented!("TODO: get_or_create player");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(mut self) -> ! {
|
pub fn run(mut self) -> ! {
|
||||||
|
@ -457,13 +418,21 @@ impl App {
|
||||||
if let Some(path) = pick_file() {
|
if let Some(path) = pick_file() {
|
||||||
// TODO: Show dialog on error.
|
// TODO: Show dialog on error.
|
||||||
let url = parse_url(&path).expect("Couldn't load specified path");
|
let url = parse_url(&path).expect("Couldn't load specified path");
|
||||||
let _ = self.load_swf(url);
|
self.player.create(
|
||||||
|
&self.opt,
|
||||||
|
url,
|
||||||
|
self.gui.lock().expect("Gui lock").create_movie_view(),
|
||||||
|
);
|
||||||
self.gui.lock().expect("Gui lock").set_ui_visible(false);
|
self.gui.lock().expect("Gui lock").set_ui_visible(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
winit::event::Event::UserEvent(RuffleEvent::OpenURL(url)) => {
|
winit::event::Event::UserEvent(RuffleEvent::OpenURL(url)) => {
|
||||||
let _ = self.load_swf(url);
|
self.player.create(
|
||||||
|
&self.opt,
|
||||||
|
url,
|
||||||
|
self.gui.lock().expect("Gui lock").create_movie_view(),
|
||||||
|
);
|
||||||
self.gui.lock().expect("Gui lock").set_ui_visible(false);
|
self.gui.lock().expect("Gui lock").set_ui_visible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::cli::Opt;
|
||||||
use crate::custom_event::RuffleEvent;
|
use crate::custom_event::RuffleEvent;
|
||||||
use crate::executor::GlutinAsyncExecutor;
|
use crate::executor::GlutinAsyncExecutor;
|
||||||
use crate::gui::MovieView;
|
use crate::gui::MovieView;
|
||||||
use crate::RENDER_INFO;
|
use crate::{CALLSTACK, RENDER_INFO, SWF_INFO};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use ruffle_core::backend::audio::AudioBackend;
|
use ruffle_core::backend::audio::AudioBackend;
|
||||||
use ruffle_core::{Player, PlayerBuilder};
|
use ruffle_core::{Player, PlayerBuilder};
|
||||||
|
@ -16,16 +16,16 @@ use url::Url;
|
||||||
use winit::event_loop::EventLoopProxy;
|
use winit::event_loop::EventLoopProxy;
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
|
||||||
pub struct PlayerController {
|
struct ActivePlayer {
|
||||||
player: Arc<Mutex<Player>>,
|
player: Arc<Mutex<Player>>,
|
||||||
executor: Arc<Mutex<GlutinAsyncExecutor>>,
|
executor: Arc<Mutex<GlutinAsyncExecutor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlayerController {
|
impl ActivePlayer {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
opt: &Opt,
|
opt: &Opt,
|
||||||
event_loop: EventLoopProxy<RuffleEvent>,
|
event_loop: EventLoopProxy<RuffleEvent>,
|
||||||
movie_url: Option<Url>,
|
movie_url: Url,
|
||||||
window: Rc<Window>,
|
window: Rc<Window>,
|
||||||
descriptors: Arc<Descriptors>,
|
descriptors: Arc<Descriptors>,
|
||||||
movie_view: MovieView,
|
movie_view: MovieView,
|
||||||
|
@ -44,11 +44,9 @@ impl PlayerController {
|
||||||
|
|
||||||
let (executor, channel) = GlutinAsyncExecutor::new(event_loop.clone());
|
let (executor, channel) = GlutinAsyncExecutor::new(event_loop.clone());
|
||||||
let navigator = crate::navigator::ExternalNavigatorBackend::new(
|
let navigator = crate::navigator::ExternalNavigatorBackend::new(
|
||||||
opt.base.to_owned().unwrap_or(
|
opt.base.to_owned().unwrap_or_else(|| movie_url.clone()),
|
||||||
movie_url.unwrap_or_else(|| Url::parse("file:///empty").expect("Dummy Url")),
|
|
||||||
),
|
|
||||||
channel,
|
channel,
|
||||||
event_loop,
|
event_loop.clone(),
|
||||||
opt.proxy.clone(),
|
opt.proxy.clone(),
|
||||||
opt.upgrade_to_https,
|
opt.upgrade_to_https,
|
||||||
opt.open_url_mode,
|
opt.open_url_mode,
|
||||||
|
@ -70,7 +68,10 @@ impl PlayerController {
|
||||||
.with_storage(
|
.with_storage(
|
||||||
crate::storage::DiskStorageBackend::new().expect("Couldn't create storage backend"),
|
crate::storage::DiskStorageBackend::new().expect("Couldn't create storage backend"),
|
||||||
)
|
)
|
||||||
.with_ui(crate::ui::DesktopUiBackend::new(window).expect("Couldn't create ui backend"))
|
.with_ui(
|
||||||
|
crate::ui::DesktopUiBackend::new(window.clone())
|
||||||
|
.expect("Couldn't create ui backend"),
|
||||||
|
)
|
||||||
.with_autoplay(true)
|
.with_autoplay(true)
|
||||||
.with_letterbox(opt.letterbox)
|
.with_letterbox(opt.letterbox)
|
||||||
.with_max_execution_duration(Duration::from_secs_f64(opt.max_execution_duration))
|
.with_max_execution_duration(Duration::from_secs_f64(opt.max_execution_duration))
|
||||||
|
@ -82,26 +83,89 @@ impl PlayerController {
|
||||||
.with_spoofed_url(opt.spoof_url.clone().map(|url| url.to_string()))
|
.with_spoofed_url(opt.spoof_url.clone().map(|url| url.to_string()))
|
||||||
.with_player_version(opt.player_version)
|
.with_player_version(opt.player_version)
|
||||||
.with_frame_rate(opt.frame_rate);
|
.with_frame_rate(opt.frame_rate);
|
||||||
|
let player = builder.build();
|
||||||
|
|
||||||
Self {
|
let name = movie_url
|
||||||
player: builder.build(),
|
.path_segments()
|
||||||
executor,
|
.and_then(|segments| segments.last())
|
||||||
|
.unwrap_or_else(|| movie_url.as_str())
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
window.set_title(&format!("Ruffle - {name}"));
|
||||||
|
|
||||||
|
SWF_INFO.with(|i| *i.borrow_mut() = Some(name.clone()));
|
||||||
|
|
||||||
|
let on_metadata = move |swf_header: &ruffle_core::swf::HeaderExt| {
|
||||||
|
let _ = event_loop.send_event(RuffleEvent::OnMetadata(swf_header.clone()));
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut parameters: Vec<(String, String)> = movie_url.query_pairs().into_owned().collect();
|
||||||
|
parameters.extend(opt.parameters());
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut player_lock = player.lock().expect("Player lock must be available");
|
||||||
|
CALLSTACK.with(|callstack| {
|
||||||
|
*callstack.borrow_mut() = Some(player_lock.callstack());
|
||||||
|
});
|
||||||
|
player_lock.fetch_root_movie(movie_url.to_string(), parameters, Box::new(on_metadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Self { player, executor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PlayerController {
|
||||||
|
player: Option<ActivePlayer>,
|
||||||
|
event_loop: EventLoopProxy<RuffleEvent>,
|
||||||
|
window: Rc<Window>,
|
||||||
|
descriptors: Arc<Descriptors>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlayerController {
|
||||||
|
pub fn new(
|
||||||
|
event_loop: EventLoopProxy<RuffleEvent>,
|
||||||
|
window: Rc<Window>,
|
||||||
|
descriptors: Arc<Descriptors>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
player: None,
|
||||||
|
event_loop,
|
||||||
|
window,
|
||||||
|
descriptors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(&mut self, opt: &Opt, movie_url: Url, movie_view: MovieView) {
|
||||||
|
self.player = Some(ActivePlayer::new(
|
||||||
|
opt,
|
||||||
|
self.event_loop.clone(),
|
||||||
|
movie_url,
|
||||||
|
self.window.clone(),
|
||||||
|
self.descriptors.clone(),
|
||||||
|
movie_view,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> Option<MutexGuard<Player>> {
|
pub fn get(&self) -> Option<MutexGuard<Player>> {
|
||||||
|
match &self.player {
|
||||||
|
None => None,
|
||||||
// We don't want to return None when the lock fails to grab as that's a fatal error, not a lack of player
|
// We don't want to return None when the lock fails to grab as that's a fatal error, not a lack of player
|
||||||
Some(
|
Some(player) => Some(
|
||||||
self.player
|
player
|
||||||
|
.player
|
||||||
.try_lock()
|
.try_lock()
|
||||||
.expect("Player lock must be available"),
|
.expect("Player lock must be available"),
|
||||||
)
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll(&self) {
|
pub fn poll(&self) {
|
||||||
self.executor
|
if let Some(player) = &self.player {
|
||||||
|
player
|
||||||
|
.executor
|
||||||
.lock()
|
.lock()
|
||||||
.expect("active executor reference")
|
.expect("Executor lock must be available")
|
||||||
.poll_all()
|
.poll_all()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue