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,
|
||||
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<Window>,
|
||||
event_loop: Option<EventLoop<RuffleEvent>>,
|
||||
event_loop_proxy: EventLoopProxy<RuffleEvent>,
|
||||
gui: Arc<Mutex<GuiController>>,
|
||||
player: PlayerController,
|
||||
min_window_size: LogicalSize<u32>,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Mutex<Player>>,
|
||||
executor: Arc<Mutex<GlutinAsyncExecutor>>,
|
||||
}
|
||||
|
||||
impl PlayerController {
|
||||
impl ActivePlayer {
|
||||
pub fn new(
|
||||
opt: &Opt,
|
||||
event_loop: EventLoopProxy<RuffleEvent>,
|
||||
movie_url: Option<Url>,
|
||||
movie_url: Url,
|
||||
window: Rc<Window>,
|
||||
descriptors: Arc<Descriptors>,
|
||||
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();
|
||||
|
||||
Self {
|
||||
player: builder.build(),
|
||||
executor,
|
||||
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<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>> {
|
||||
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(
|
||||
self.player
|
||||
Some(player) => Some(
|
||||
player
|
||||
.player
|
||||
.try_lock()
|
||||
.expect("Player lock must be available"),
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn poll(&self) {
|
||||
self.executor
|
||||
if let Some(player) = &self.player {
|
||||
player
|
||||
.executor
|
||||
.lock()
|
||||
.expect("active executor reference")
|
||||
.expect("Executor lock must be available")
|
||||
.poll_all()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue