mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
servo: Add a BluetoothDeviceSelectionRequest to the API for selecting Bluetooth devices (#43580)
This change has 2 parts: - adding `BluetoothPickDeviceRequest`, similar to other request structs used to communicate with the embedder. - switch from a `Vec<String>` that expected 2 * <device count> strings to `Vec<BluetoothDeviceDescription>` which is easier to reason about. Testing: Manual testing with a build that has the `native-bluetooth` feature enabled. --------- Signed-off-by: webbeef <me@webbeef.org>
This commit is contained in:
@@ -10,12 +10,12 @@ use egui::{
|
||||
};
|
||||
use egui_file_dialog::{DialogState, FileDialog as EguiFileDialog};
|
||||
use euclid::Length;
|
||||
use log::warn;
|
||||
use log::{error, warn};
|
||||
use servo::{
|
||||
AlertDialog, AuthenticationRequest, ColorPicker, ConfirmDialog, ContextMenu, ContextMenuItem,
|
||||
DeviceIndependentPixel, EmbedderControlId, FilePicker, GenericSender, PermissionRequest,
|
||||
PromptDialog, RgbColor, SelectElement, SelectElementOption, SelectElementOptionOrOptgroup,
|
||||
SimpleDialog,
|
||||
AlertDialog, AuthenticationRequest, BluetoothDeviceSelectionRequest, ColorPicker,
|
||||
ConfirmDialog, ContextMenu, ContextMenuItem, DeviceIndependentPixel, EmbedderControlId,
|
||||
FilePicker, PermissionRequest, PromptDialog, RgbColor, SelectElement, SelectElementOption,
|
||||
SelectElementOptionOrOptgroup, SimpleDialog,
|
||||
};
|
||||
|
||||
/// The minimum width of many UI elements including dialog boxes and menus,
|
||||
@@ -41,9 +41,8 @@ pub enum Dialog {
|
||||
request: Option<PermissionRequest>,
|
||||
},
|
||||
SelectDevice {
|
||||
devices: Vec<String>,
|
||||
request: Option<BluetoothDeviceSelectionRequest>,
|
||||
selected_device_index: usize,
|
||||
response_sender: GenericSender<Option<String>>,
|
||||
},
|
||||
SelectElement {
|
||||
maybe_prompt: Option<SelectElement>,
|
||||
@@ -113,14 +112,10 @@ impl Dialog {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_device_selection_dialog(
|
||||
devices: Vec<String>,
|
||||
response_sender: GenericSender<Option<String>>,
|
||||
) -> Self {
|
||||
pub fn new_device_selection_dialog(request: BluetoothDeviceSelectionRequest) -> Self {
|
||||
Dialog::SelectDevice {
|
||||
devices,
|
||||
request: Some(request),
|
||||
selected_device_index: 0,
|
||||
response_sender,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,29 +401,36 @@ impl Dialog {
|
||||
is_open
|
||||
},
|
||||
Dialog::SelectDevice {
|
||||
devices,
|
||||
request,
|
||||
selected_device_index,
|
||||
response_sender,
|
||||
} => {
|
||||
let mut is_open = true;
|
||||
let modal = Modal::new("device_picker".into());
|
||||
modal.show(ctx, |ui| {
|
||||
let mut frame = egui::Frame::default().inner_margin(10.0).begin(ui);
|
||||
frame.content_ui.set_min_width(MINIMUM_UI_ELEMENT_WIDTH);
|
||||
if let Some(request) = request {
|
||||
let mut frame = egui::Frame::default().inner_margin(10.0).begin(ui);
|
||||
frame.content_ui.set_min_width(MINIMUM_UI_ELEMENT_WIDTH);
|
||||
|
||||
frame.content_ui.heading("Choose a Device");
|
||||
frame.content_ui.add_space(10.0);
|
||||
frame.content_ui.heading("Choose a Device");
|
||||
frame.content_ui.add_space(10.0);
|
||||
|
||||
egui::ComboBox::from_label("")
|
||||
.selected_text(&devices[*selected_device_index + 1])
|
||||
.show_ui(&mut frame.content_ui, |ui| {
|
||||
for i in (0..devices.len() - 1).step_by(2) {
|
||||
let device_name = &devices[i + 1];
|
||||
ui.selectable_value(selected_device_index, i, device_name);
|
||||
}
|
||||
});
|
||||
let devices = request.devices();
|
||||
egui::ComboBox::from_label("")
|
||||
.selected_text(devices[*selected_device_index].name.clone())
|
||||
.show_ui(&mut frame.content_ui, |ui| {
|
||||
for (i, device) in devices.iter().enumerate() {
|
||||
ui.selectable_value(
|
||||
selected_device_index,
|
||||
i,
|
||||
device.name.clone(),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
frame.end(ui);
|
||||
frame.end(ui);
|
||||
} else {
|
||||
error!("Unexpected: None SelectDevice while the dialog is open");
|
||||
}
|
||||
|
||||
egui::Sides::new().show(
|
||||
ui,
|
||||
@@ -437,18 +439,21 @@ impl Dialog {
|
||||
if ui.button("Ok").clicked() ||
|
||||
ui.input(|i| i.key_pressed(egui::Key::Enter))
|
||||
{
|
||||
if let Err(e) = response_sender
|
||||
.send(Some(devices[*selected_device_index].clone()))
|
||||
{
|
||||
warn!("Failed to send device selection: {}", e);
|
||||
let request =
|
||||
request.take().expect("non-None until dialog is closed");
|
||||
let choice = &request.devices()[*selected_device_index].clone();
|
||||
if let Err(error) = request.pick_device(choice) {
|
||||
warn!("Failed to send device selection: {error}");
|
||||
}
|
||||
is_open = false;
|
||||
}
|
||||
if ui.button("Cancel").clicked() ||
|
||||
ui.input(|i| i.key_pressed(egui::Key::Escape))
|
||||
{
|
||||
if let Err(e) = response_sender.send(None) {
|
||||
warn!("Failed to send cancellation: {}", e);
|
||||
let request =
|
||||
request.take().expect("non-None until dialog is closed");
|
||||
if let Err(error) = request.cancel() {
|
||||
warn!("Failed to send cancellation: {error}");
|
||||
}
|
||||
is_open = false;
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ use keyboard_types::ShortcutMatcher;
|
||||
use log::{debug, info};
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
|
||||
use servo::{
|
||||
AuthenticationRequest, Cursor, DeviceIndependentIntRect, DeviceIndependentPixel,
|
||||
DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint, EmbedderControl,
|
||||
EmbedderControlId, GenericSender, ImeEvent, InputEvent, InputEventId, InputEventResult,
|
||||
AuthenticationRequest, BluetoothDeviceSelectionRequest, Cursor, DeviceIndependentIntRect,
|
||||
DeviceIndependentPixel, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint,
|
||||
EmbedderControl, EmbedderControlId, ImeEvent, InputEvent, InputEventId, InputEventResult,
|
||||
InputMethodControl, Key, KeyState, KeyboardEvent, Modifiers, MouseButton as ServoMouseButton,
|
||||
MouseButtonAction, MouseButtonEvent, MouseLeftViewportEvent, MouseMoveEvent, NamedKey,
|
||||
OffscreenRenderingContext, PermissionRequest, RenderingContext, ScreenGeometry, Theme,
|
||||
@@ -1106,18 +1106,9 @@ impl PlatformWindow for HeadedWindow {
|
||||
fn show_bluetooth_device_dialog(
|
||||
&self,
|
||||
webview_id: WebViewId,
|
||||
devices: Vec<String>,
|
||||
response_sender: GenericSender<Option<String>>,
|
||||
request: BluetoothDeviceSelectionRequest,
|
||||
) {
|
||||
if devices.is_empty() {
|
||||
let _ = response_sender.send(None);
|
||||
return;
|
||||
}
|
||||
|
||||
self.add_dialog(
|
||||
webview_id,
|
||||
Dialog::new_device_selection_dialog(devices, response_sender),
|
||||
);
|
||||
self.add_dialog(webview_id, Dialog::new_device_selection_dialog(request));
|
||||
}
|
||||
|
||||
fn show_permission_dialog(&self, webview_id: WebViewId, permission_request: PermissionRequest) {
|
||||
|
||||
@@ -19,13 +19,13 @@ use image::{DynamicImage, ImageFormat, RgbaImage};
|
||||
use libc::c_char;
|
||||
use log::{error, info, warn};
|
||||
use servo::{
|
||||
AllowOrDenyRequest, AuthenticationRequest, CSSPixel, ConsoleLogLevel, CreateNewWebViewRequest,
|
||||
DeviceIntPoint, DeviceIntSize, EmbedderControl, EmbedderControlId, EventLoopWaker,
|
||||
GenericSender, InputEvent, InputEventId, InputEventResult, JSValue, LoadStatus,
|
||||
MediaSessionEvent, PermissionRequest, PrefValue, Preferences, ScreenshotCaptureError, Servo,
|
||||
ServoDelegate, ServoError, TraversalId, UserContentManager, WebDriverCommandMsg,
|
||||
WebDriverJSResult, WebDriverLoadStatus, WebDriverScriptCommand, WebDriverSenders, WebView,
|
||||
WebViewDelegate, WebViewId, pref,
|
||||
AllowOrDenyRequest, AuthenticationRequest, BluetoothDeviceSelectionRequest, CSSPixel,
|
||||
ConsoleLogLevel, CreateNewWebViewRequest, DeviceIntPoint, DeviceIntSize, EmbedderControl,
|
||||
EmbedderControlId, EventLoopWaker, GenericSender, InputEvent, InputEventId, InputEventResult,
|
||||
JSValue, LoadStatus, MediaSessionEvent, PermissionRequest, PrefValue, Preferences,
|
||||
ScreenshotCaptureError, Servo, ServoDelegate, ServoError, TraversalId, UserContentManager,
|
||||
WebDriverCommandMsg, WebDriverJSResult, WebDriverLoadStatus, WebDriverScriptCommand,
|
||||
WebDriverSenders, WebView, WebViewDelegate, WebViewId, pref,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
@@ -779,11 +779,10 @@ impl WebViewDelegate for RunningAppState {
|
||||
fn show_bluetooth_device_dialog(
|
||||
&self,
|
||||
webview: WebView,
|
||||
devices: Vec<String>,
|
||||
response_sender: GenericSender<Option<String>>,
|
||||
request: BluetoothDeviceSelectionRequest,
|
||||
) {
|
||||
self.platform_window_for_webview_id(webview.id())
|
||||
.show_bluetooth_device_dialog(webview.id(), devices, response_sender);
|
||||
.show_bluetooth_device_dialog(webview.id(), request);
|
||||
}
|
||||
|
||||
fn request_permission(&self, webview: WebView, permission_request: PermissionRequest) {
|
||||
|
||||
@@ -8,9 +8,9 @@ use std::rc::Rc;
|
||||
use euclid::Scale;
|
||||
use log::warn;
|
||||
use servo::{
|
||||
AuthenticationRequest, ConsoleLogLevel, Cursor, DeviceIndependentIntRect,
|
||||
DeviceIndependentPixel, DeviceIntPoint, DeviceIntSize, DevicePixel, EmbedderControl,
|
||||
EmbedderControlId, GenericSender, InputEventId, InputEventResult, MediaSessionEvent,
|
||||
AuthenticationRequest, BluetoothDeviceSelectionRequest, ConsoleLogLevel, Cursor,
|
||||
DeviceIndependentIntRect, DeviceIndependentPixel, DeviceIntPoint, DeviceIntSize, DevicePixel,
|
||||
EmbedderControl, EmbedderControlId, InputEventId, InputEventResult, MediaSessionEvent,
|
||||
PermissionRequest, RenderingContext, ScreenGeometry, WebView, WebViewBuilder, WebViewId,
|
||||
};
|
||||
use url::Url;
|
||||
@@ -412,8 +412,7 @@ pub(crate) trait PlatformWindow {
|
||||
fn show_bluetooth_device_dialog(
|
||||
&self,
|
||||
_: WebViewId,
|
||||
_devices: Vec<String>,
|
||||
_: GenericSender<Option<String>>,
|
||||
_request: BluetoothDeviceSelectionRequest,
|
||||
) {
|
||||
}
|
||||
fn show_permission_dialog(&self, _: WebViewId, _: PermissionRequest) {}
|
||||
|
||||
Reference in New Issue
Block a user