From e97d32dbc7fb4fda42f686fff455daad035789fa Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sun, 21 May 2023 22:23:43 +0200 Subject: [PATCH] desktop: Recreate Player for each movie, and don't start with a Player unless a movie has been specified --- desktop/src/app.rs | 67 +++++++------------------- desktop/src/player.rs | 106 +++++++++++++++++++++++++++++++++--------- 2 files changed, 103 insertions(+), 70 deletions(-) diff --git a/desktop/src/app.rs b/desktop/src/app.rs index 66aec3678..289a3e10d 100644 --- a/desktop/src/app.rs +++ b/desktop/src/app.rs @@ -6,7 +6,6 @@ use crate::util::{ get_screen_size, parse_url, pick_file, winit_key_to_char, winit_to_ruffle_key_code, winit_to_ruffle_text_control, }; -use crate::{CALLSTACK, SWF_INFO}; use anyhow::{Context, Error}; use ruffle_core::{PlayerEvent, StageDisplayState}; use ruffle_render::backend::ViewportDimensions; @@ -14,17 +13,15 @@ use ruffle_render_wgpu::backend::WgpuRenderBackend; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::Instant; -use url::Url; use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Size}; 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}; pub struct App { opt: Opt, window: Rc, event_loop: Option>, - event_loop_proxy: EventLoopProxy, gui: Arc>, player: PlayerController, min_window_size: LogicalSize, @@ -65,61 +62,25 @@ impl App { opt.power.into(), )?; - let player = PlayerController::new( - &opt, + let mut player = PlayerController::new( event_loop.create_proxy(), - movie_url.clone(), window.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, window, - event_loop_proxy: event_loop.create_proxy(), event_loop: Some(event_loop), gui: Arc::new(Mutex::new(gui)), player, min_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) -> ! { @@ -457,13 +418,21 @@ impl App { if let Some(path) = pick_file() { // TODO: Show dialog on error. 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); } } 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); } diff --git a/desktop/src/player.rs b/desktop/src/player.rs index ac9b9bdb0..7a98b6a92 100644 --- a/desktop/src/player.rs +++ b/desktop/src/player.rs @@ -2,7 +2,7 @@ use crate::cli::Opt; use crate::custom_event::RuffleEvent; use crate::executor::GlutinAsyncExecutor; use crate::gui::MovieView; -use crate::RENDER_INFO; +use crate::{CALLSTACK, RENDER_INFO, SWF_INFO}; use anyhow::anyhow; use ruffle_core::backend::audio::AudioBackend; use ruffle_core::{Player, PlayerBuilder}; @@ -16,16 +16,16 @@ use url::Url; use winit::event_loop::EventLoopProxy; use winit::window::Window; -pub struct PlayerController { +struct ActivePlayer { player: Arc>, executor: Arc>, } -impl PlayerController { +impl ActivePlayer { pub fn new( opt: &Opt, event_loop: EventLoopProxy, - movie_url: Option, + movie_url: Url, window: Rc, descriptors: Arc, movie_view: MovieView, @@ -44,11 +44,9 @@ impl PlayerController { let (executor, channel) = GlutinAsyncExecutor::new(event_loop.clone()); let navigator = crate::navigator::ExternalNavigatorBackend::new( - opt.base.to_owned().unwrap_or( - movie_url.unwrap_or_else(|| Url::parse("file:///empty").expect("Dummy Url")), - ), + opt.base.to_owned().unwrap_or_else(|| movie_url.clone()), channel, - event_loop, + event_loop.clone(), opt.proxy.clone(), opt.upgrade_to_https, opt.open_url_mode, @@ -70,7 +68,10 @@ impl PlayerController { .with_storage( 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_letterbox(opt.letterbox) .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_player_version(opt.player_version) .with_frame_rate(opt.frame_rate); + let player = builder.build(); + let name = movie_url + .path_segments() + .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, + event_loop: EventLoopProxy, + window: Rc, + descriptors: Arc, +} + +impl PlayerController { + pub fn new( + event_loop: EventLoopProxy, + window: Rc, + descriptors: Arc, + ) -> Self { Self { - player: builder.build(), - executor, + 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> { - // 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( - self.player - .try_lock() - .expect("Player lock must be available"), - ) + 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 + Some(player) => Some( + player + .player + .try_lock() + .expect("Player lock must be available"), + ), + } } pub fn poll(&self) { - self.executor - .lock() - .expect("active executor reference") - .poll_all() + if let Some(player) = &self.player { + player + .executor + .lock() + .expect("Executor lock must be available") + .poll_all() + } } }