mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
Expose a GamepadProvider and use Responder types for messages (#41568)
Expose a `GamepadProvider` and use `Responder` types for messages Testing: Fixes: https://github.com/servo/servo/issues/41453 --------- Signed-off-by: atbrakhi <atbrakhi@igalia.com>
This commit is contained in:
67
components/servo/gamepad_provider.rs
Normal file
67
components/servo/gamepad_provider.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use embedder_traits::GamepadHapticEffectType;
|
||||
|
||||
pub enum GamepadHapticEffectRequestType {
|
||||
Play(GamepadHapticEffectType),
|
||||
Stop,
|
||||
}
|
||||
|
||||
pub struct GamepadHapticEffectRequest {
|
||||
gamepad_index: usize,
|
||||
request_type: GamepadHapticEffectRequestType,
|
||||
callback: Option<Box<dyn FnOnce(bool)>>,
|
||||
}
|
||||
|
||||
impl GamepadHapticEffectRequest {
|
||||
pub(crate) fn new(
|
||||
gamepad_index: usize,
|
||||
request_type: GamepadHapticEffectRequestType,
|
||||
callback: Box<dyn FnOnce(bool)>,
|
||||
) -> Self {
|
||||
Self {
|
||||
gamepad_index,
|
||||
request_type,
|
||||
callback: Some(callback),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gamepad_index(&self) -> usize {
|
||||
self.gamepad_index
|
||||
}
|
||||
|
||||
pub fn request_type(&self) -> &GamepadHapticEffectRequestType {
|
||||
&self.request_type
|
||||
}
|
||||
|
||||
pub fn failed(mut self) {
|
||||
if let Some(callback) = self.callback.take() {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn succeeded(mut self) {
|
||||
if let Some(callback) = self.callback.take() {
|
||||
callback(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GamepadHapticEffectRequest {
|
||||
fn drop(&mut self) {
|
||||
if let Some(callback) = self.callback.take() {
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GamepadProvider {
|
||||
/// Handle a request to play or stop a haptic effect on a connected gamepad.
|
||||
fn handle_haptic_effect_request(&self, _request: GamepadHapticEffectRequest) {}
|
||||
}
|
||||
|
||||
pub(crate) struct DefaultGamepadProvider;
|
||||
|
||||
impl GamepadProvider for DefaultGamepadProvider {}
|
||||
@@ -13,6 +13,8 @@
|
||||
//! `ScriptThread` and the `LayoutThread`, as well maintains the navigation context.
|
||||
|
||||
mod clipboard_delegate;
|
||||
#[cfg(feature = "gamepad")]
|
||||
mod gamepad_provider;
|
||||
mod javascript_evaluator;
|
||||
mod network_manager;
|
||||
mod proxies;
|
||||
@@ -61,6 +63,10 @@ pub use webrender_api::units::{
|
||||
DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint, DeviceVector2D,
|
||||
};
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
pub use crate::gamepad_provider::{
|
||||
GamepadHapticEffectRequest, GamepadHapticEffectRequestType, GamepadProvider,
|
||||
};
|
||||
pub use crate::network_manager::{CacheEntry, NetworkManager};
|
||||
pub use crate::servo::{Servo, ServoBuilder, run_content_process};
|
||||
pub use crate::servo_delegate::{ServoDelegate, ServoError};
|
||||
|
||||
@@ -74,6 +74,8 @@ use storage_traits::StorageThreads;
|
||||
use style::global_style_data::StyleThreadPool;
|
||||
|
||||
use crate::clipboard_delegate::StringRequest;
|
||||
#[cfg(feature = "gamepad")]
|
||||
use crate::gamepad_provider::{GamepadHapticEffectRequest, GamepadHapticEffectRequestType};
|
||||
use crate::javascript_evaluator::JavaScriptEvaluator;
|
||||
use crate::network_manager::NetworkManager;
|
||||
use crate::proxies::ConstellationProxy;
|
||||
@@ -586,30 +588,35 @@ impl ServoInner {
|
||||
callback,
|
||||
) => {
|
||||
if let Some(webview) = self.get_webview_handle(webview_id) {
|
||||
webview.delegate().play_gamepad_haptic_effect(
|
||||
webview,
|
||||
let request = GamepadHapticEffectRequest::new(
|
||||
gamepad_index,
|
||||
gamepad_haptic_effect_type,
|
||||
GamepadHapticEffectRequestType::Play(gamepad_haptic_effect_type),
|
||||
Box::new(move |success| {
|
||||
callback
|
||||
.send(success)
|
||||
.expect("Could not send message via callback")
|
||||
}),
|
||||
);
|
||||
webview
|
||||
.gamepad_provider()
|
||||
.handle_haptic_effect_request(request);
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "gamepad")]
|
||||
EmbedderMsg::StopGamepadHapticEffect(webview_id, gamepad_index, callback) => {
|
||||
if let Some(webview) = self.get_webview_handle(webview_id) {
|
||||
webview.delegate().stop_gamepad_haptic_effect(
|
||||
webview,
|
||||
let request = GamepadHapticEffectRequest::new(
|
||||
gamepad_index,
|
||||
GamepadHapticEffectRequestType::Stop,
|
||||
Box::new(move |success| {
|
||||
callback
|
||||
.send(success)
|
||||
.expect("Could not send message via callback")
|
||||
}),
|
||||
);
|
||||
webview
|
||||
.gamepad_provider()
|
||||
.handle_haptic_effect_request(request);
|
||||
}
|
||||
},
|
||||
EmbedderMsg::ShowNotification(webview_id, notification) => {
|
||||
|
||||
@@ -28,6 +28,8 @@ use url::Url;
|
||||
use webrender_api::units::{DeviceIntRect, DevicePixel, DevicePoint, DeviceSize};
|
||||
|
||||
use crate::clipboard_delegate::{ClipboardDelegate, DefaultClipboardDelegate};
|
||||
#[cfg(feature = "gamepad")]
|
||||
use crate::gamepad_provider::{DefaultGamepadProvider, GamepadProvider};
|
||||
use crate::responders::IpcResponder;
|
||||
use crate::webview_delegate::{CreateNewWebViewRequest, DefaultWebViewDelegate, WebViewDelegate};
|
||||
use crate::{
|
||||
@@ -84,6 +86,8 @@ pub(crate) struct WebViewInner {
|
||||
pub(crate) servo: Servo,
|
||||
pub(crate) delegate: Rc<dyn WebViewDelegate>,
|
||||
pub(crate) clipboard_delegate: Rc<dyn ClipboardDelegate>,
|
||||
#[cfg(feature = "gamepad")]
|
||||
pub(crate) gamepad_provider: Rc<dyn GamepadProvider>,
|
||||
|
||||
rendering_context: Rc<dyn RenderingContext>,
|
||||
user_content_manager: Option<Rc<UserContentManager>>,
|
||||
@@ -126,6 +130,8 @@ impl WebView {
|
||||
rendering_context: builder.rendering_context,
|
||||
delegate: builder.delegate,
|
||||
clipboard_delegate: Rc::new(DefaultClipboardDelegate),
|
||||
#[cfg(feature = "gamepad")]
|
||||
gamepad_provider: Rc::new(DefaultGamepadProvider),
|
||||
hidpi_scale_factor: builder.hidpi_scale_factor,
|
||||
load_status: LoadStatus::Started,
|
||||
status_text: None,
|
||||
@@ -245,6 +251,16 @@ impl WebView {
|
||||
self.inner_mut().clipboard_delegate = delegate;
|
||||
}
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
pub fn gamepad_provider(&self) -> Rc<dyn GamepadProvider> {
|
||||
self.inner().gamepad_provider.clone()
|
||||
}
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
pub fn set_gamepad_provider(&self, provider: Rc<dyn GamepadProvider>) {
|
||||
self.inner_mut().gamepad_provider = provider;
|
||||
}
|
||||
|
||||
pub fn id(&self) -> WebViewId {
|
||||
self.inner().id
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ use crate::desktop::tracing::trace_winit_event;
|
||||
use crate::parser::get_default_url;
|
||||
use crate::prefs::ServoShellPreferences;
|
||||
use crate::running_app_state::RunningAppState;
|
||||
#[cfg(feature = "gamepad")]
|
||||
use crate::running_app_state::ServoshellGamepadProvider;
|
||||
use crate::window::{PlatformWindow, ServoShellWindowId};
|
||||
|
||||
pub(crate) enum AppState {
|
||||
@@ -123,6 +125,8 @@ impl App {
|
||||
self.waker.clone(),
|
||||
user_content_manager,
|
||||
self.preferences.clone(),
|
||||
#[cfg(feature = "gamepad")]
|
||||
ServoshellGamepadProvider::maybe_new().map(Rc::new),
|
||||
));
|
||||
running_state.open_window(platform_window, self.initial_url.as_url().clone());
|
||||
|
||||
|
||||
@@ -2,27 +2,29 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use gilrs::ff::{BaseEffect, BaseEffectType, Effect, EffectBuilder, Repeat, Replay, Ticks};
|
||||
use gilrs::{EventType, Gilrs};
|
||||
use log::{debug, warn};
|
||||
use servo::{
|
||||
GamepadEvent, GamepadHapticEffectType, GamepadIndex, GamepadInputBounds,
|
||||
GamepadEvent, GamepadHapticEffectRequest, GamepadHapticEffectRequestType,
|
||||
GamepadHapticEffectType, GamepadIndex, GamepadInputBounds, GamepadProvider,
|
||||
GamepadSupportedHapticEffects, GamepadUpdateType, InputEvent, WebView,
|
||||
};
|
||||
|
||||
pub struct HapticEffect {
|
||||
pub effect: Effect,
|
||||
pub callback: Option<Box<dyn FnOnce(bool)>>,
|
||||
pub request: GamepadHapticEffectRequest,
|
||||
}
|
||||
|
||||
pub(crate) struct GamepadSupport {
|
||||
handle: Gilrs,
|
||||
haptic_effects: HashMap<usize, HapticEffect>,
|
||||
pub(crate) struct ServoshellGamepadProvider {
|
||||
handle: RefCell<Gilrs>,
|
||||
haptic_effects: RefCell<HashMap<usize, HapticEffect>>,
|
||||
}
|
||||
|
||||
impl GamepadSupport {
|
||||
impl ServoshellGamepadProvider {
|
||||
pub(crate) fn maybe_new() -> Option<Self> {
|
||||
let handle = match Gilrs::new() {
|
||||
Ok(handle) => handle,
|
||||
@@ -32,15 +34,16 @@ impl GamepadSupport {
|
||||
},
|
||||
};
|
||||
Some(Self {
|
||||
handle,
|
||||
haptic_effects: Default::default(),
|
||||
handle: RefCell::new(handle),
|
||||
haptic_effects: RefCell::new(Default::default()),
|
||||
})
|
||||
}
|
||||
|
||||
/// Handle updates to connected gamepads from GilRs
|
||||
pub(crate) fn handle_gamepad_events(&mut self, active_webview: WebView) {
|
||||
while let Some(event) = self.handle.next_event() {
|
||||
let gamepad = self.handle.gamepad(event.id);
|
||||
pub(crate) fn handle_gamepad_events(&self, active_webview: WebView) {
|
||||
let mut handle = self.handle.borrow_mut();
|
||||
while let Some(event) = handle.next_event() {
|
||||
let gamepad = handle.gamepad(event.id);
|
||||
let name = gamepad.name();
|
||||
let index = GamepadIndex(event.id.into());
|
||||
let mut gamepad_event: Option<GamepadEvent> = None;
|
||||
@@ -113,14 +116,13 @@ impl GamepadSupport {
|
||||
gamepad_event = Some(GamepadEvent::Disconnected(index));
|
||||
},
|
||||
EventType::ForceFeedbackEffectCompleted => {
|
||||
let Some(effect) = self.haptic_effects.get_mut(&event.id.into()) else {
|
||||
if let Some(haptic_effect) =
|
||||
self.haptic_effects.borrow_mut().remove(&event.id.into())
|
||||
{
|
||||
haptic_effect.request.succeeded();
|
||||
} else {
|
||||
warn!("Failed to find haptic effect for id {}", event.id);
|
||||
return;
|
||||
};
|
||||
if let Some(callback) = effect.callback.take() {
|
||||
callback(true);
|
||||
}
|
||||
self.haptic_effects.remove(&event.id.into());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
@@ -156,62 +158,71 @@ impl GamepadSupport {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn play_haptic_effect(
|
||||
&mut self,
|
||||
index: usize,
|
||||
effect_type: GamepadHapticEffectType,
|
||||
callback: Box<dyn FnOnce(bool)>,
|
||||
fn play_haptic_effect(
|
||||
&self,
|
||||
effect_type: &GamepadHapticEffectType,
|
||||
request: GamepadHapticEffectRequest,
|
||||
) {
|
||||
let index = request.gamepad_index();
|
||||
let GamepadHapticEffectType::DualRumble(params) = effect_type;
|
||||
if let Some(connected_gamepad) = self
|
||||
.handle
|
||||
|
||||
let mut handle = self.handle.borrow_mut();
|
||||
let Some(connected_gamepad) = handle
|
||||
.gamepads()
|
||||
.find(|gamepad| usize::from(gamepad.0) == index)
|
||||
{
|
||||
let start_delay = Ticks::from_ms(params.start_delay as u32);
|
||||
let duration = Ticks::from_ms(params.duration as u32);
|
||||
let strong_magnitude = (params.strong_magnitude * u16::MAX as f64).round() as u16;
|
||||
let weak_magnitude = (params.weak_magnitude * u16::MAX as f64).round() as u16;
|
||||
|
||||
let scheduling = Replay {
|
||||
after: start_delay,
|
||||
play_for: duration,
|
||||
with_delay: Ticks::from_ms(0),
|
||||
};
|
||||
let effect = EffectBuilder::new()
|
||||
.add_effect(BaseEffect {
|
||||
kind: BaseEffectType::Strong { magnitude: strong_magnitude },
|
||||
scheduling,
|
||||
envelope: Default::default(),
|
||||
})
|
||||
.add_effect(BaseEffect {
|
||||
kind: BaseEffectType::Weak { magnitude: weak_magnitude },
|
||||
scheduling,
|
||||
envelope: Default::default(),
|
||||
})
|
||||
.repeat(Repeat::For(start_delay + duration))
|
||||
.add_gamepad(&connected_gamepad.1)
|
||||
.finish(&mut self.handle)
|
||||
.expect("Failed to create haptic effect, ensure connected gamepad supports force feedback.");
|
||||
self.haptic_effects.insert(
|
||||
index,
|
||||
HapticEffect {
|
||||
effect,
|
||||
callback: Some(callback),
|
||||
},
|
||||
);
|
||||
self.haptic_effects[&index]
|
||||
.effect
|
||||
.play()
|
||||
.expect("Failed to play haptic effect.");
|
||||
} else {
|
||||
else {
|
||||
debug!("Couldn't find connected gamepad to play haptic effect on");
|
||||
}
|
||||
request.failed();
|
||||
return;
|
||||
};
|
||||
|
||||
let start_delay = Ticks::from_ms(params.start_delay as u32);
|
||||
let duration = Ticks::from_ms(params.duration as u32);
|
||||
let strong_magnitude = (params.strong_magnitude * u16::MAX as f64).round() as u16;
|
||||
let weak_magnitude = (params.weak_magnitude * u16::MAX as f64).round() as u16;
|
||||
|
||||
let scheduling = Replay {
|
||||
after: start_delay,
|
||||
play_for: duration,
|
||||
with_delay: Ticks::from_ms(0),
|
||||
};
|
||||
let effect = EffectBuilder::new()
|
||||
.add_effect(BaseEffect {
|
||||
kind: BaseEffectType::Strong {
|
||||
magnitude: strong_magnitude,
|
||||
},
|
||||
scheduling,
|
||||
envelope: Default::default(),
|
||||
})
|
||||
.add_effect(BaseEffect {
|
||||
kind: BaseEffectType::Weak {
|
||||
magnitude: weak_magnitude,
|
||||
},
|
||||
scheduling,
|
||||
envelope: Default::default(),
|
||||
})
|
||||
.repeat(Repeat::For(start_delay + duration))
|
||||
.add_gamepad(&connected_gamepad.1)
|
||||
.finish(&mut handle)
|
||||
.expect(
|
||||
"Failed to create haptic effect, ensure connected gamepad supports force feedback.",
|
||||
);
|
||||
|
||||
let mut haptic_effects = self.haptic_effects.borrow_mut();
|
||||
haptic_effects.insert(index, HapticEffect { effect, request });
|
||||
haptic_effects[&index]
|
||||
.effect
|
||||
.play()
|
||||
.expect("Failed to play haptic effect.");
|
||||
}
|
||||
|
||||
pub(crate) fn stop_haptic_effect(&mut self, index: usize) -> bool {
|
||||
let Some(haptic_effect) = self.haptic_effects.get(&index) else {
|
||||
return false;
|
||||
fn stop_haptic_effect(&self, request: GamepadHapticEffectRequest) {
|
||||
let index = request.gamepad_index();
|
||||
|
||||
let mut haptic_effects = self.haptic_effects.borrow_mut();
|
||||
let Some(haptic_effect) = haptic_effects.get(&index) else {
|
||||
request.failed();
|
||||
return;
|
||||
};
|
||||
|
||||
let stopped_successfully = match haptic_effect.effect.stop() {
|
||||
@@ -221,8 +232,25 @@ impl GamepadSupport {
|
||||
false
|
||||
},
|
||||
};
|
||||
self.haptic_effects.remove(&index);
|
||||
haptic_effects.remove(&index);
|
||||
|
||||
stopped_successfully
|
||||
if stopped_successfully {
|
||||
request.succeeded();
|
||||
} else {
|
||||
request.failed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GamepadProvider for ServoshellGamepadProvider {
|
||||
fn handle_haptic_effect_request(&self, request: GamepadHapticEffectRequest) {
|
||||
match request.request_type() {
|
||||
GamepadHapticEffectRequestType::Play(effect_type) => {
|
||||
self.play_haptic_effect(&effect_type.clone(), request);
|
||||
},
|
||||
GamepadHapticEffectRequestType::Stop => {
|
||||
self.stop_haptic_effect(request);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use servo::{GamepadHapticEffectType, WebView};
|
||||
|
||||
/// A dummy version of [`crate::desktop::GamepadSupport`] used to avoid conditional compilation in
|
||||
/// servoshell and as a skeleton to implement gamepad support for platforms that do not
|
||||
/// currently support it.
|
||||
pub(crate) struct GamepadSupport;
|
||||
|
||||
impl GamepadSupport {
|
||||
pub(crate) fn maybe_new() -> Option<Self> {
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn handle_gamepad_events(&mut self, _active_webview: WebView) {
|
||||
unreachable!("Dummy gamepad support should never be called.");
|
||||
}
|
||||
|
||||
pub(crate) fn play_haptic_effect(
|
||||
&mut self,
|
||||
_index: usize,
|
||||
_effect_type: GamepadHapticEffectType,
|
||||
_effect_complete_callback: Box<dyn FnOnce(bool)>,
|
||||
) {
|
||||
unreachable!("Dummy gamepad support should never be called.");
|
||||
}
|
||||
|
||||
pub(crate) fn stop_haptic_effect(&mut self, _index: usize) -> bool {
|
||||
unreachable!("Dummy gamepad support should never be called.");
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@
|
||||
#[cfg(target_os = "android")]
|
||||
mod android;
|
||||
pub(crate) mod app;
|
||||
#[cfg(feature = "gamepad")]
|
||||
pub(crate) mod gamepad;
|
||||
mod host_trait;
|
||||
mod log;
|
||||
#[cfg(target_env = "ohos")]
|
||||
|
||||
@@ -25,14 +25,6 @@ mod running_app_state;
|
||||
mod webdriver;
|
||||
mod window;
|
||||
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
pub(crate) use crate::desktop::gamepad::GamepadSupport;
|
||||
#[cfg(all(feature = "gamepad", any(target_os = "android", target_env = "ohos")))]
|
||||
pub(crate) use crate::egl::gamepad::GamepadSupport;
|
||||
|
||||
pub mod platform {
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use crate::platform::macos::deinit;
|
||||
|
||||
@@ -13,8 +13,6 @@ use crossbeam_channel::{Receiver, Sender, unbounded};
|
||||
use euclid::Rect;
|
||||
use image::{DynamicImage, ImageFormat, RgbaImage};
|
||||
use log::{error, info, warn};
|
||||
#[cfg(feature = "gamepad")]
|
||||
use servo::GamepadHapticEffectType;
|
||||
use servo::{
|
||||
AllowOrDenyRequest, AuthenticationRequest, CSSPixel, ConsoleLogLevel, CreateNewWebViewRequest,
|
||||
DeviceIntPoint, DeviceIntSize, EmbedderControl, EmbedderControlId, EventLoopWaker,
|
||||
@@ -26,8 +24,11 @@ use servo::{
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
use crate::GamepadSupport;
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
pub(crate) use crate::desktop::gamepad::ServoshellGamepadProvider;
|
||||
use crate::prefs::{EXPERIMENTAL_PREFS, ServoShellPreferences};
|
||||
use crate::webdriver::WebDriverEmbedderControls;
|
||||
use crate::window::{PlatformWindow, ServoShellWindow, ServoShellWindowId};
|
||||
@@ -148,9 +149,13 @@ pub(crate) enum UserInterfaceCommand {
|
||||
}
|
||||
|
||||
pub(crate) struct RunningAppState {
|
||||
/// Gamepad support, which may be `None` if it failed to initialize.
|
||||
#[cfg(feature = "gamepad")]
|
||||
gamepad_support: RefCell<Option<GamepadSupport>>,
|
||||
/// The gamepad provider, used for handling gamepad events and set on each WebView.
|
||||
/// May be `None` if gamepad support is disabled or failed to initialize.
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
gamepad_provider: Option<Rc<ServoshellGamepadProvider>>,
|
||||
|
||||
/// The [`WebDriverSenders`] used to reply to pending WebDriver requests.
|
||||
pub(crate) webdriver_senders: RefCell<WebDriverSenders>,
|
||||
@@ -206,16 +211,14 @@ impl RunningAppState {
|
||||
event_loop_waker: Box<dyn EventLoopWaker>,
|
||||
user_content_manager: Rc<UserContentManager>,
|
||||
default_preferences: Preferences,
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
gamepad_provider: Option<Rc<ServoshellGamepadProvider>>,
|
||||
) -> Self {
|
||||
servo.set_delegate(Rc::new(ServoShellServoDelegate));
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
let gamepad_support = if pref!(dom_gamepad_enabled) {
|
||||
GamepadSupport::maybe_new()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let webdriver_receiver = servoshell_preferences.webdriver_port.get().map(|port| {
|
||||
let (embedder_sender, embedder_receiver) = unbounded();
|
||||
webdriver_server::start_server(
|
||||
@@ -233,8 +236,11 @@ impl RunningAppState {
|
||||
Self {
|
||||
windows: Default::default(),
|
||||
focused_window: Default::default(),
|
||||
#[cfg(feature = "gamepad")]
|
||||
gamepad_support: RefCell::new(gamepad_support),
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
gamepad_provider,
|
||||
webdriver_senders: RefCell::default(),
|
||||
webdriver_embedder_controls: Default::default(),
|
||||
pending_webdriver_events: Default::default(),
|
||||
@@ -300,6 +306,14 @@ impl RunningAppState {
|
||||
&self.servo
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
pub(crate) fn gamepad_provider(&self) -> Option<Rc<ServoshellGamepadProvider>> {
|
||||
self.gamepad_provider.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn schedule_exit(&self) {
|
||||
// When explicitly required to shutdown, unset webdriver port
|
||||
// which allows normal shutdown.
|
||||
@@ -361,7 +375,10 @@ impl RunningAppState {
|
||||
|
||||
self.handle_webdriver_messages(create_platform_window);
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
if pref!(dom_gamepad_enabled) {
|
||||
self.handle_gamepad_events();
|
||||
}
|
||||
@@ -565,17 +582,21 @@ impl RunningAppState {
|
||||
webview.load(url);
|
||||
}
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
pub(crate) fn handle_gamepad_events(&self) {
|
||||
let Some(gamepad_provider) = self.gamepad_provider.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let Some(active_webview) = self
|
||||
.focused_window()
|
||||
.and_then(|window| window.active_webview())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if let Some(gamepad_support) = self.gamepad_support.borrow_mut().as_mut() {
|
||||
gamepad_support.handle_gamepad_events(active_webview);
|
||||
}
|
||||
gamepad_provider.handle_gamepad_events(active_webview);
|
||||
}
|
||||
|
||||
pub(crate) fn handle_focused(&self, window: Rc<ServoShellWindow>) {
|
||||
@@ -738,38 +759,6 @@ impl WebViewDelegate for RunningAppState {
|
||||
self.window_for_webview_id(webview.id()).set_needs_repaint();
|
||||
}
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
fn play_gamepad_haptic_effect(
|
||||
&self,
|
||||
_webview: WebView,
|
||||
index: usize,
|
||||
effect_type: GamepadHapticEffectType,
|
||||
effect_complete_callback: Box<dyn FnOnce(bool)>,
|
||||
) {
|
||||
match self.gamepad_support.borrow_mut().as_mut() {
|
||||
Some(gamepad_support) => {
|
||||
gamepad_support.play_haptic_effect(index, effect_type, effect_complete_callback);
|
||||
},
|
||||
None => {
|
||||
effect_complete_callback(false);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
fn stop_gamepad_haptic_effect(
|
||||
&self,
|
||||
_webview: WebView,
|
||||
index: usize,
|
||||
haptic_stop_callback: Box<dyn FnOnce(bool)>,
|
||||
) {
|
||||
let stopped = match self.gamepad_support.borrow_mut().as_mut() {
|
||||
Some(gamepad_support) => gamepad_support.stop_haptic_effect(index),
|
||||
None => false,
|
||||
};
|
||||
haptic_stop_callback(stopped);
|
||||
}
|
||||
|
||||
fn show_embedder_control(&self, webview: WebView, embedder_control: EmbedderControl) {
|
||||
if self.servoshell_preferences.webdriver_port.get().is_some() {
|
||||
if matches!(&embedder_control, EmbedderControl::SimpleDialog(..)) {
|
||||
|
||||
@@ -92,6 +92,14 @@ impl ServoShellWindow {
|
||||
.delegate(state.clone())
|
||||
.build();
|
||||
|
||||
#[cfg(all(
|
||||
feature = "gamepad",
|
||||
not(any(target_os = "android", target_env = "ohos"))
|
||||
))]
|
||||
if let Some(gamepad_provider) = state.gamepad_provider() {
|
||||
webview.set_gamepad_provider(gamepad_provider);
|
||||
}
|
||||
|
||||
webview.notify_theme_change(self.platform_window.theme());
|
||||
self.add_webview(webview.clone());
|
||||
webview
|
||||
|
||||
Reference in New Issue
Block a user