feat(core): add tauri-wry crate (#1756)

This commit is contained in:
Lucas Fernandes Nogueira 2021-05-09 18:43:50 -03:00 committed by GitHub
parent f190f11f13
commit 45a7a111e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 433 additions and 276 deletions

View File

@ -220,7 +220,16 @@
"dependencies": [
"tauri-utils"
],
"postversion": "node ../../.scripts/sync-prerelease.js ${ release.type }"
"postversion": "node ../../.scripts/sync-prerelease.js ${ pkg.pkg } ${ release.type }"
},
"tauri-runtime-wry": {
"path": "./core/tauri-runtime-wry",
"manager": "rust",
"dependencies": [
"tauri-utils",
"tauri-runtime"
],
"postversion": "node ../../.scripts/sync-prerelease.js ${ pkg.pkg } ${ release.type }"
},
"tauri-codegen": {
"path": "./core/tauri-codegen",
@ -250,7 +259,8 @@
"dependencies": [
"tauri-macros",
"tauri-utils",
"tauri-runtime"
"tauri-runtime",
"tauri-runtime-wry"
],
"postversion": "node ../../.scripts/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }"
},

View File

@ -1,5 +1,5 @@
---
"tauri-runtime": patch
"tauri-runtime": minor
"tauri": patch
---

6
.changes/tauri-wry.md Normal file
View File

@ -0,0 +1,6 @@
---
"tauri": patch
"tauri-runtime-wry": minor
---
`tauri-runtime-wry` initial release.

View File

@ -10,15 +10,28 @@ keep the `tauri-release` crate version without the `beta` or `beta-rc` suffix.
const { readFileSync, writeFileSync } = require("fs")
const runtimeManifestPath = '../../core/tauri-runtime/Cargo.toml'
const dependencyManifestPaths = ['../../core/tauri/Cargo.toml']
const changelogPath = '../../core/tauri-runtime/CHANGELOG.md'
const packageNickname = process.argv[2]
const bump = process.argv[3]
const bump = process.argv[2]
let manifestPath
let dependencyManifestPaths
let changelogPath
let runtimeManifest = readFileSync(runtimeManifestPath, "utf-8")
runtimeManifest = runtimeManifest.replace(/version = "(\d+\.\d+\.\d+)-[^0-9\.]+\.0"/, 'version = "$1"')
writeFileSync(runtimeManifestPath, runtimeManifest)
if (packageNickname === 'tauri-runtime') {
manifestPath = '../../core/tauri-runtime/Cargo.toml'
dependencyManifestPaths = ['../../core/tauri/Cargo.toml', '../../core/tauri-runtime-wry/Cargo.toml']
changelogPath = '../../core/tauri-runtime/CHANGELOG.md'
} else if (packageNickname === 'tauri-runtime-wry') {
manifestPath = '../../core/tauri-runtime-wry/Cargo.toml'
dependencyManifestPaths = ['../../core/tauri/Cargo.toml']
changelogPath = '../../core/tauri-runtime-wry/CHANGELOG.md'
} else {
throw new Error(`Unexpected package ${packageNickname}`)
}
let manifest = readFileSync(manifestPath, "utf-8")
manifest = manifest.replace(/version = "(\d+\.\d+\.\d+)-[^0-9\.]+\.0"/, 'version = "$1"')
writeFileSync(manifestPath, manifest)
let changelog = readFileSync(changelogPath, "utf-8")
changelog = changelog.replace(/(\d+\.\d+\.\d+)-[^0-9\.]+\.0/, '$1')

View File

@ -3,6 +3,7 @@ members = [
# core
"core/tauri",
"core/tauri-runtime",
"core/tauri-runtime-wry",
"core/tauri-macros",
"core/tauri-utils",
"core/tauri-build",

View File

@ -0,0 +1,3 @@
// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

View File

@ -0,0 +1,17 @@
[package]
name = "tauri-runtime-wry"
version = "0.0.0"
authors = [ "Tauri Programme within The Commons Conservancy" ]
categories = [ "gui", "web-programming" ]
license = "Apache-2.0 OR MIT"
homepage = "https://tauri.studio"
repository = "https://github.com/tauri-apps/tauri"
description = "Wry bindings to the Tauri runtime"
edition = "2018"
[dependencies]
wry = { git = "https://github.com/tauri-apps/wry", rev = "6bc97aff525644b83a3a00537316c46d7afb985b" }
tauri-runtime = { version = "0.0.0", path = "../tauri-runtime" }
tauri-utils = { version = "1.0.0-beta-rc.1", path = "../tauri-utils" }
image = "0.23"
uuid = { version = "0.8.2", features = [ "v4" ] }

View File

@ -4,8 +4,9 @@
//! The [`wry`] Tauri [`Runtime`].
use crate::{
use tauri_runtime::{
menu::{CustomMenuItem, Menu, MenuId, MenuItem, SystemTrayMenuItem},
monitor::Monitor,
webview::{
FileDropEvent, FileDropHandler, RpcRequest, WebviewRpcHandler, WindowBuilder, WindowBuilderBase,
},
@ -13,7 +14,7 @@ use crate::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
DetachedWindow, MenuEvent, PendingWindow, WindowEvent,
},
Dispatch, Icon, Monitor, Params, Runtime, SystemTrayEvent,
Dispatch, Error, Icon, Params, Result, Runtime, SystemTrayEvent,
};
use image::{GenericImageView, Pixel};
@ -52,7 +53,7 @@ use std::{
};
type CreateWebviewHandler =
Box<dyn FnOnce(&EventLoopWindowTarget<Message>) -> crate::Result<WebView> + Send>;
Box<dyn FnOnce(&EventLoopWindowTarget<Message>) -> Result<WebView> + Send>;
type MainThreadTask = Box<dyn FnOnce() + Send>;
type WindowEventHandler = Box<dyn Fn(&WindowEvent) + Send>;
type WindowEventListeners = Arc<Mutex<HashMap<Uuid, WindowEventHandler>>>;
@ -76,21 +77,22 @@ const PIXEL_SIZE: usize = std::mem::size_of::<PixelValue>();
pub struct WryIcon(WindowIcon);
impl TryFrom<Icon> for WryIcon {
type Error = crate::Error;
fn try_from(icon: Icon) -> Result<Self, Self::Error> {
type Error = Error;
fn try_from(icon: Icon) -> std::result::Result<Self, Self::Error> {
let image = match icon {
Icon::File(path) => image::open(path).map_err(|e| crate::Error::InvalidIcon(Box::new(e)))?,
Icon::File(path) => image::open(path).map_err(|e| Error::InvalidIcon(Box::new(e)))?,
Icon::Raw(raw) => {
image::load_from_memory(&raw).map_err(|e| crate::Error::InvalidIcon(Box::new(e)))?
image::load_from_memory(&raw).map_err(|e| Error::InvalidIcon(Box::new(e)))?
}
_ => unimplemented!(),
};
let (width, height) = image.dimensions();
let mut rgba = Vec::with_capacity((width * height) as usize * PIXEL_SIZE);
for (_, _, pixel) in image.pixels() {
rgba.extend_from_slice(&pixel.to_rgba().0);
}
let icon = WindowIcon::from_rgba(rgba, width, height)
.map_err(|e| crate::Error::InvalidIcon(Box::new(e)))?;
let icon =
WindowIcon::from_rgba(rgba, width, height).map_err(|e| Error::InvalidIcon(Box::new(e)))?;
Ok(Self(icon))
}
}
@ -100,8 +102,10 @@ struct WindowEventWrapper(Option<WindowEvent>);
impl<'a> From<&WryWindowEvent<'a>> for WindowEventWrapper {
fn from(event: &WryWindowEvent<'a>) -> Self {
let event = match event {
WryWindowEvent::Resized(size) => WindowEvent::Resized((*size).into()),
WryWindowEvent::Moved(position) => WindowEvent::Moved((*position).into()),
WryWindowEvent::Resized(size) => WindowEvent::Resized(PhysicalSizeWrapper(*size).into()),
WryWindowEvent::Moved(position) => {
WindowEvent::Moved(PhysicalPositionWrapper(*position).into())
}
WryWindowEvent::CloseRequested => WindowEvent::CloseRequested,
WryWindowEvent::Destroyed => WindowEvent::Destroyed,
WryWindowEvent::Focused(focused) => WindowEvent::Focused(*focused),
@ -110,7 +114,7 @@ impl<'a> From<&WryWindowEvent<'a>> for WindowEventWrapper {
new_inner_size,
} => WindowEvent::ScaleFactorChanged {
scale_factor: *scale_factor,
new_inner_size: (**new_inner_size).into(),
new_inner_size: PhysicalSizeWrapper(**new_inner_size).into(),
},
_ => return Self(None),
};
@ -118,150 +122,181 @@ impl<'a> From<&WryWindowEvent<'a>> for WindowEventWrapper {
}
}
impl From<MonitorHandle> for Monitor {
fn from(monitor: MonitorHandle) -> Monitor {
pub struct MonitorHandleWrapper(MonitorHandle);
impl From<MonitorHandleWrapper> for Monitor {
fn from(monitor: MonitorHandleWrapper) -> Monitor {
Self {
name: monitor.name(),
position: monitor.position().into(),
size: monitor.size().into(),
scale_factor: monitor.scale_factor(),
name: monitor.0.name(),
position: PhysicalPositionWrapper(monitor.0.position()).into(),
size: PhysicalSizeWrapper(monitor.0.size()).into(),
scale_factor: monitor.0.scale_factor(),
}
}
}
impl<T> From<WryPhysicalPosition<T>> for PhysicalPosition<T> {
fn from(position: WryPhysicalPosition<T>) -> Self {
struct PhysicalPositionWrapper<T>(WryPhysicalPosition<T>);
impl<T> From<PhysicalPositionWrapper<T>> for PhysicalPosition<T> {
fn from(position: PhysicalPositionWrapper<T>) -> Self {
Self {
x: position.x,
y: position.y,
x: position.0.x,
y: position.0.y,
}
}
}
impl<T> From<PhysicalPosition<T>> for WryPhysicalPosition<T> {
impl<T> From<PhysicalPosition<T>> for PhysicalPositionWrapper<T> {
fn from(position: PhysicalPosition<T>) -> Self {
Self {
Self(WryPhysicalPosition {
x: position.x,
y: position.y,
}
})
}
}
impl<T> From<LogicalPosition<T>> for WryLogicalPosition<T> {
struct LogicalPositionWrapper<T>(WryLogicalPosition<T>);
impl<T> From<LogicalPosition<T>> for LogicalPositionWrapper<T> {
fn from(position: LogicalPosition<T>) -> Self {
Self {
Self(WryLogicalPosition {
x: position.x,
y: position.y,
}
})
}
}
impl<T> From<WryPhysicalSize<T>> for PhysicalSize<T> {
fn from(size: WryPhysicalSize<T>) -> Self {
struct PhysicalSizeWrapper<T>(WryPhysicalSize<T>);
impl<T> From<PhysicalSizeWrapper<T>> for PhysicalSize<T> {
fn from(size: PhysicalSizeWrapper<T>) -> Self {
Self {
width: size.width,
height: size.height,
width: size.0.width,
height: size.0.height,
}
}
}
impl<T> From<PhysicalSize<T>> for WryPhysicalSize<T> {
impl<T> From<PhysicalSize<T>> for PhysicalSizeWrapper<T> {
fn from(size: PhysicalSize<T>) -> Self {
Self {
Self(WryPhysicalSize {
width: size.width,
height: size.height,
}
})
}
}
impl<T> From<LogicalSize<T>> for WryLogicalSize<T> {
struct LogicalSizeWrapper<T>(WryLogicalSize<T>);
impl<T> From<LogicalSize<T>> for LogicalSizeWrapper<T> {
fn from(size: LogicalSize<T>) -> Self {
Self {
Self(WryLogicalSize {
width: size.width,
height: size.height,
}
})
}
}
impl From<Size> for WrySize {
struct SizeWrapper(WrySize);
impl From<Size> for SizeWrapper {
fn from(size: Size) -> Self {
match size {
Size::Logical(s) => Self::Logical(s.into()),
Size::Physical(s) => Self::Physical(s.into()),
Size::Logical(s) => Self(WrySize::Logical(LogicalSizeWrapper::from(s).0)),
Size::Physical(s) => Self(WrySize::Physical(PhysicalSizeWrapper::from(s).0)),
}
}
}
impl From<Position> for WryPosition {
struct PositionWrapper(WryPosition);
impl From<Position> for PositionWrapper {
fn from(position: Position) -> Self {
match position {
Position::Logical(s) => Self::Logical(s.into()),
Position::Physical(s) => Self::Physical(s.into()),
Position::Logical(s) => Self(WryPosition::Logical(LogicalPositionWrapper::from(s).0)),
Position::Physical(s) => Self(WryPosition::Physical(PhysicalPositionWrapper::from(s).0)),
}
}
}
impl<I: MenuId> From<CustomMenuItem<I>> for WryCustomMenu {
pub struct CustomMenuWrapper(WryCustomMenu);
impl<I: MenuId> From<CustomMenuItem<I>> for CustomMenuWrapper {
fn from(item: CustomMenuItem<I>) -> Self {
Self {
Self(WryCustomMenu {
id: WryMenuId(item.id_value()),
name: item.name,
keyboard_accelerators: None,
}
})
}
}
impl<I: MenuId> From<MenuItem<I>> for WryMenuItem {
struct MenuItemWrapper(WryMenuItem);
impl<I: MenuId> From<MenuItem<I>> for MenuItemWrapper {
fn from(item: MenuItem<I>) -> Self {
match item {
MenuItem::Custom(custom) => Self::Custom(custom.into()),
MenuItem::About(v) => Self::About(v),
MenuItem::Hide => Self::Hide,
MenuItem::Services => Self::Services,
MenuItem::HideOthers => Self::HideOthers,
MenuItem::ShowAll => Self::ShowAll,
MenuItem::CloseWindow => Self::CloseWindow,
MenuItem::Quit => Self::Quit,
MenuItem::Copy => Self::Copy,
MenuItem::Cut => Self::Cut,
MenuItem::Undo => Self::Undo,
MenuItem::Redo => Self::Redo,
MenuItem::SelectAll => Self::SelectAll,
MenuItem::Paste => Self::Paste,
MenuItem::EnterFullScreen => Self::EnterFullScreen,
MenuItem::Minimize => Self::Minimize,
MenuItem::Zoom => Self::Zoom,
MenuItem::Separator => Self::Separator,
MenuItem::Custom(custom) => Self(WryMenuItem::Custom(CustomMenuWrapper::from(custom).0)),
MenuItem::About(v) => Self(WryMenuItem::About(v)),
MenuItem::Hide => Self(WryMenuItem::Hide),
MenuItem::Services => Self(WryMenuItem::Services),
MenuItem::HideOthers => Self(WryMenuItem::HideOthers),
MenuItem::ShowAll => Self(WryMenuItem::ShowAll),
MenuItem::CloseWindow => Self(WryMenuItem::CloseWindow),
MenuItem::Quit => Self(WryMenuItem::Quit),
MenuItem::Copy => Self(WryMenuItem::Copy),
MenuItem::Cut => Self(WryMenuItem::Cut),
MenuItem::Undo => Self(WryMenuItem::Undo),
MenuItem::Redo => Self(WryMenuItem::Redo),
MenuItem::SelectAll => Self(WryMenuItem::SelectAll),
MenuItem::Paste => Self(WryMenuItem::Paste),
MenuItem::EnterFullScreen => Self(WryMenuItem::EnterFullScreen),
MenuItem::Minimize => Self(WryMenuItem::Minimize),
MenuItem::Zoom => Self(WryMenuItem::Zoom),
MenuItem::Separator => Self(WryMenuItem::Separator),
_ => unimplemented!(),
}
}
}
impl<I: MenuId> From<Menu<I>> for WryMenu {
pub struct MenuWrapper(WryMenu);
impl<I: MenuId> From<Menu<I>> for MenuWrapper {
fn from(menu: Menu<I>) -> Self {
Self {
Self(WryMenu {
title: menu.title,
items: menu.items.into_iter().map(Into::into).collect(),
}
items: menu
.items
.into_iter()
.map(|m| MenuItemWrapper::from(m).0)
.collect(),
})
}
}
impl<I: MenuId> From<SystemTrayMenuItem<I>> for WryMenuItem {
impl<I: MenuId> From<SystemTrayMenuItem<I>> for MenuItemWrapper {
fn from(item: SystemTrayMenuItem<I>) -> Self {
match item {
SystemTrayMenuItem::Custom(custom) => Self::Custom(custom.into()),
SystemTrayMenuItem::Separator => Self::Separator,
SystemTrayMenuItem::Custom(custom) => {
Self(WryMenuItem::Custom(CustomMenuWrapper::from(custom).0))
}
SystemTrayMenuItem::Separator => Self(WryMenuItem::Separator),
_ => unimplemented!(),
}
}
}
impl WindowBuilderBase for WryWindowBuilder {}
impl WindowBuilder for WryWindowBuilder {
#[derive(Debug, Clone, Default)]
pub struct WindowBuilderWrapper(WryWindowBuilder);
impl WindowBuilderBase for WindowBuilderWrapper {}
impl WindowBuilder for WindowBuilderWrapper {
fn new() -> Self {
Default::default()
}
fn with_config(config: WindowConfig) -> Self {
let mut window = WryWindowBuilder::new()
let mut window = WindowBuilderWrapper::new()
.title(config.title.to_string())
.inner_size(config.width, config.height)
.visible(config.visible)
@ -286,86 +321,107 @@ impl WindowBuilder for WryWindowBuilder {
}
fn menu<I: MenuId>(self, menu: Vec<Menu<I>>) -> Self {
self.with_menu(menu.into_iter().map(Into::into).collect::<Vec<WryMenu>>())
Self(
self.0.with_menu(
menu
.into_iter()
.map(|m| MenuWrapper::from(m).0)
.collect::<Vec<WryMenu>>(),
),
)
}
fn position(self, x: f64, y: f64) -> Self {
self.with_position(WryLogicalPosition::new(x, y))
Self(self.0.with_position(WryLogicalPosition::new(x, y)))
}
fn inner_size(self, width: f64, height: f64) -> Self {
self.with_inner_size(WryLogicalSize::new(width, height))
Self(self.0.with_inner_size(WryLogicalSize::new(width, height)))
}
fn min_inner_size(self, min_width: f64, min_height: f64) -> Self {
self.with_min_inner_size(WryLogicalSize::new(min_width, min_height))
Self(
self
.0
.with_min_inner_size(WryLogicalSize::new(min_width, min_height)),
)
}
fn max_inner_size(self, max_width: f64, max_height: f64) -> Self {
self.with_max_inner_size(WryLogicalSize::new(max_width, max_height))
Self(
self
.0
.with_max_inner_size(WryLogicalSize::new(max_width, max_height)),
)
}
fn resizable(self, resizable: bool) -> Self {
self.with_resizable(resizable)
Self(self.0.with_resizable(resizable))
}
fn title<S: Into<String>>(self, title: S) -> Self {
self.with_title(title.into())
Self(self.0.with_title(title.into()))
}
fn fullscreen(self, fullscreen: bool) -> Self {
if fullscreen {
self.with_fullscreen(Some(Fullscreen::Borderless(None)))
Self(self.0.with_fullscreen(Some(Fullscreen::Borderless(None))))
} else {
self.with_fullscreen(None)
Self(self.0.with_fullscreen(None))
}
}
fn maximized(self, maximized: bool) -> Self {
self.with_maximized(maximized)
Self(self.0.with_maximized(maximized))
}
fn visible(self, visible: bool) -> Self {
self.with_visible(visible)
Self(self.0.with_visible(visible))
}
fn transparent(self, transparent: bool) -> Self {
self.with_transparent(transparent)
Self(self.0.with_transparent(transparent))
}
fn decorations(self, decorations: bool) -> Self {
self.with_decorations(decorations)
Self(self.0.with_decorations(decorations))
}
fn always_on_top(self, always_on_top: bool) -> Self {
self.with_always_on_top(always_on_top)
Self(self.0.with_always_on_top(always_on_top))
}
fn icon(self, icon: Icon) -> crate::Result<Self> {
Ok(self.with_window_icon(Some(WryIcon::try_from(icon)?.0)))
fn icon(self, icon: Icon) -> Result<Self> {
Ok(Self(
self.0.with_window_icon(Some(WryIcon::try_from(icon)?.0)),
))
}
fn has_icon(&self) -> bool {
self.window.window_icon.is_some()
self.0.window.window_icon.is_some()
}
fn has_menu(&self) -> bool {
self.window.window_menu.is_some()
self.0.window.window_menu.is_some()
}
}
impl From<WryRpcRequest> for RpcRequest {
fn from(request: WryRpcRequest) -> Self {
pub struct RpcRequestWrapper(WryRpcRequest);
impl From<RpcRequestWrapper> for RpcRequest {
fn from(request: RpcRequestWrapper) -> Self {
Self {
command: request.method,
params: request.params,
command: request.0.method,
params: request.0.params,
}
}
}
impl From<WryFileDropEvent> for FileDropEvent {
fn from(event: WryFileDropEvent) -> Self {
match event {
pub struct FileDropEventWrapper(WryFileDropEvent);
impl From<FileDropEventWrapper> for FileDropEvent {
fn from(event: FileDropEventWrapper) -> Self {
match event.0 {
WryFileDropEvent::Hovered(paths) => FileDropEvent::Hovered(paths),
WryFileDropEvent::Dropped(paths) => FileDropEvent::Dropped(paths),
WryFileDropEvent::Cancelled => FileDropEvent::Cancelled,
@ -377,8 +433,8 @@ impl From<WryFileDropEvent> for FileDropEvent {
enum WindowMessage {
// Getters
ScaleFactor(Sender<f64>),
InnerPosition(Sender<crate::Result<PhysicalPosition<i32>>>),
OuterPosition(Sender<crate::Result<PhysicalPosition<i32>>>),
InnerPosition(Sender<Result<PhysicalPosition<i32>>>),
OuterPosition(Sender<Result<PhysicalPosition<i32>>>),
InnerSize(Sender<PhysicalSize<u32>>),
OuterSize(Sender<PhysicalSize<u32>>),
IsFullscreen(Sender<bool>),
@ -442,40 +498,21 @@ macro_rules! dispatcher_getter {
.context
.proxy
.send_event(Message::Window($self.window_id, $message(tx)))
.map_err(|_| crate::Error::FailedToSendMessage)?;
.map_err(|_| Error::FailedToSendMessage)?;
rx.recv().unwrap()
}};
}
macro_rules! window_result_getter {
($window: ident, $tx: ident, $call: ident) => {
$tx
.send(
$window
.$call()
.map(Into::into)
.map_err(|_| crate::Error::FailedToSendMessage),
)
.unwrap()
};
}
macro_rules! window_getter {
($window: ident, $tx: ident, $call: ident) => {
$tx.send($window.$call().into()).unwrap()
};
}
impl Dispatch for WryDispatcher {
type Runtime = Wry;
type WindowBuilder = WryWindowBuilder;
type WindowBuilder = WindowBuilderWrapper;
fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> crate::Result<()> {
fn run_on_main_thread<F: FnOnce() + Send + 'static>(&self, f: F) -> Result<()> {
self
.context
.task_tx
.send(Box::new(f))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn on_window_event<F: Fn(&WindowEvent) + Send + 'static>(&self, f: F) -> Uuid {
@ -502,65 +539,71 @@ impl Dispatch for WryDispatcher {
// Getters
fn scale_factor(&self) -> crate::Result<f64> {
fn scale_factor(&self) -> Result<f64> {
Ok(dispatcher_getter!(self, WindowMessage::ScaleFactor))
}
fn inner_position(&self) -> crate::Result<PhysicalPosition<i32>> {
fn inner_position(&self) -> Result<PhysicalPosition<i32>> {
dispatcher_getter!(self, WindowMessage::InnerPosition)
}
fn outer_position(&self) -> crate::Result<PhysicalPosition<i32>> {
fn outer_position(&self) -> Result<PhysicalPosition<i32>> {
dispatcher_getter!(self, WindowMessage::OuterPosition)
}
fn inner_size(&self) -> crate::Result<PhysicalSize<u32>> {
fn inner_size(&self) -> Result<PhysicalSize<u32>> {
Ok(dispatcher_getter!(self, WindowMessage::InnerSize))
}
fn outer_size(&self) -> crate::Result<PhysicalSize<u32>> {
fn outer_size(&self) -> Result<PhysicalSize<u32>> {
Ok(dispatcher_getter!(self, WindowMessage::OuterSize))
}
fn is_fullscreen(&self) -> crate::Result<bool> {
fn is_fullscreen(&self) -> Result<bool> {
Ok(dispatcher_getter!(self, WindowMessage::IsFullscreen))
}
fn is_maximized(&self) -> crate::Result<bool> {
fn is_maximized(&self) -> Result<bool> {
Ok(dispatcher_getter!(self, WindowMessage::IsMaximized))
}
fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
Ok(dispatcher_getter!(self, WindowMessage::CurrentMonitor).map(Into::into))
fn current_monitor(&self) -> Result<Option<Monitor>> {
Ok(
dispatcher_getter!(self, WindowMessage::CurrentMonitor)
.map(|m| MonitorHandleWrapper(m).into()),
)
}
fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
Ok(dispatcher_getter!(self, WindowMessage::PrimaryMonitor).map(Into::into))
fn primary_monitor(&self) -> Result<Option<Monitor>> {
Ok(
dispatcher_getter!(self, WindowMessage::PrimaryMonitor)
.map(|m| MonitorHandleWrapper(m).into()),
)
}
fn available_monitors(&self) -> crate::Result<Vec<Monitor>> {
fn available_monitors(&self) -> Result<Vec<Monitor>> {
Ok(
dispatcher_getter!(self, WindowMessage::AvailableMonitors)
.into_iter()
.map(Into::into)
.map(|m| MonitorHandleWrapper(m).into())
.collect(),
)
}
// Setters
fn print(&self) -> crate::Result<()> {
fn print(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Webview(self.window_id, WebviewMessage::Print))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn create_window<M: Params<Runtime = Self::Runtime>>(
&mut self,
pending: PendingWindow<M>,
) -> crate::Result<DetachedWindow<M>> {
) -> Result<DetachedWindow<M>> {
let (tx, rx) = channel();
let label = pending.label.clone();
let context = self.context.clone();
@ -573,7 +616,7 @@ impl Dispatch for WryDispatcher {
})))),
tx,
))
.map_err(|_| crate::Error::FailedToSendMessage)?;
.map_err(|_| Error::FailedToSendMessage)?;
let window_id = rx.recv().unwrap();
let dispatcher = WryDispatcher {
window_id,
@ -582,7 +625,7 @@ impl Dispatch for WryDispatcher {
Ok(DetachedWindow { label, dispatcher })
}
fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
fn set_resizable(&self, resizable: bool) -> Result<()> {
self
.context
.proxy
@ -590,10 +633,10 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetResizable(resizable),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_title<S: Into<String>>(&self, title: S) -> crate::Result<()> {
fn set_title<S: Into<String>>(&self, title: S) -> Result<()> {
self
.context
.proxy
@ -601,66 +644,66 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetTitle(title.into()),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn maximize(&self) -> crate::Result<()> {
fn maximize(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Window(self.window_id, WindowMessage::Maximize))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn unmaximize(&self) -> crate::Result<()> {
fn unmaximize(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Window(self.window_id, WindowMessage::Unmaximize))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn minimize(&self) -> crate::Result<()> {
fn minimize(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Window(self.window_id, WindowMessage::Minimize))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn unminimize(&self) -> crate::Result<()> {
fn unminimize(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Window(self.window_id, WindowMessage::Unminimize))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn show(&self) -> crate::Result<()> {
fn show(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Window(self.window_id, WindowMessage::Show))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn hide(&self) -> crate::Result<()> {
fn hide(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Window(self.window_id, WindowMessage::Hide))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn close(&self) -> crate::Result<()> {
fn close(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Window(self.window_id, WindowMessage::Close))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
fn set_decorations(&self, decorations: bool) -> Result<()> {
self
.context
.proxy
@ -668,10 +711,10 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetDecorations(decorations),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
fn set_always_on_top(&self, always_on_top: bool) -> Result<()> {
self
.context
.proxy
@ -679,10 +722,10 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetAlwaysOnTop(always_on_top),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_size(&self, size: Size) -> crate::Result<()> {
fn set_size(&self, size: Size) -> Result<()> {
self
.context
.proxy
@ -690,10 +733,10 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetSize(size),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_min_size(&self, size: Option<Size>) -> crate::Result<()> {
fn set_min_size(&self, size: Option<Size>) -> Result<()> {
self
.context
.proxy
@ -701,10 +744,10 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetMinSize(size),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_max_size(&self, size: Option<Size>) -> crate::Result<()> {
fn set_max_size(&self, size: Option<Size>) -> Result<()> {
self
.context
.proxy
@ -712,10 +755,10 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetMaxSize(size),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_position(&self, position: Position) -> crate::Result<()> {
fn set_position(&self, position: Position) -> Result<()> {
self
.context
.proxy
@ -723,10 +766,10 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetPosition(position),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
self
.context
.proxy
@ -734,10 +777,10 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetFullscreen(fullscreen),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn set_icon(&self, icon: Icon) -> crate::Result<()> {
fn set_icon(&self, icon: Icon) -> Result<()> {
self
.context
.proxy
@ -745,18 +788,18 @@ impl Dispatch for WryDispatcher {
self.window_id,
WindowMessage::SetIcon(WryIcon::try_from(icon)?.0),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn start_dragging(&self) -> crate::Result<()> {
fn start_dragging(&self) -> Result<()> {
self
.context
.proxy
.send_event(Message::Window(self.window_id, WindowMessage::DragWindow))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
fn eval_script<S: Into<String>>(&self, script: S) -> crate::Result<()> {
fn eval_script<S: Into<String>>(&self, script: S) -> Result<()> {
self
.context
.proxy
@ -764,7 +807,7 @@ impl Dispatch for WryDispatcher {
self.window_id,
WebviewMessage::EvaluateScript(script.into()),
))
.map_err(|_| crate::Error::FailedToSendMessage)
.map_err(|_| Error::FailedToSendMessage)
}
}
@ -782,7 +825,7 @@ pub struct Wry {
impl Runtime for Wry {
type Dispatcher = WryDispatcher;
fn new() -> crate::Result<Self> {
fn new() -> Result<Self> {
let event_loop = EventLoop::<Message>::with_user_event();
let (task_tx, task_rx) = channel();
Ok(Self {
@ -799,7 +842,7 @@ impl Runtime for Wry {
fn create_window<M: Params<Runtime = Self>>(
&self,
pending: PendingWindow<M>,
) -> crate::Result<DetachedWindow<M>> {
) -> Result<DetachedWindow<M>> {
let label = pending.label.clone();
let proxy = self.event_loop.create_proxy();
let webview = create_webview(
@ -836,11 +879,17 @@ impl Runtime for Wry {
fn system_tray<I: MenuId>(
&self,
icon: std::path::PathBuf,
menu: Vec<SystemTrayMenuItem<I>>,
) -> crate::Result<()> {
SystemTrayBuilder::new(icon, menu.into_iter().map(Into::into).collect())
menu_items: Vec<SystemTrayMenuItem<I>>,
) -> Result<()> {
SystemTrayBuilder::new(
icon,
menu_items
.into_iter()
.map(|m| MenuItemWrapper::from(m).0)
.collect(),
)
.build(&self.event_loop)
.map_err(|e| crate::Error::SystemTray(Box::new(e)))?;
.map_err(|e| Error::SystemTray(Box::new(e)))?;
Ok(())
}
@ -848,11 +897,17 @@ impl Runtime for Wry {
fn system_tray<I: MenuId>(
&self,
icon: Vec<u8>,
menu: Vec<SystemTrayMenuItem<I>>,
) -> crate::Result<()> {
SystemTrayBuilder::new(icon, menu.into_iter().map(Into::into).collect())
menu_items: Vec<SystemTrayMenuItem<I>>,
) -> Result<()> {
SystemTrayBuilder::new(
icon,
menu_items
.into_iter()
.map(|m| MenuItemWrapper::from(m).0)
.collect(),
)
.build(&self.event_loop)
.map_err(|e| crate::Error::SystemTray(Box::new(e)))?;
.map_err(|e| Error::SystemTray(Box::new(e)))?;
Ok(())
}
@ -934,19 +989,33 @@ impl Runtime for Wry {
let window = webview.window();
match window_message {
// Getters
WindowMessage::ScaleFactor(tx) => window_getter!(window, tx, scale_factor),
WindowMessage::InnerPosition(tx) => {
window_result_getter!(window, tx, inner_position)
}
WindowMessage::OuterPosition(tx) => {
window_result_getter!(window, tx, outer_position)
}
WindowMessage::InnerSize(tx) => window_getter!(window, tx, inner_size),
WindowMessage::OuterSize(tx) => window_getter!(window, tx, outer_size),
WindowMessage::ScaleFactor(tx) => tx.send(window.scale_factor()).unwrap(),
WindowMessage::InnerPosition(tx) => tx
.send(
window
.inner_position()
.map(|p| PhysicalPositionWrapper(p).into())
.map_err(|_| Error::FailedToSendMessage),
)
.unwrap(),
WindowMessage::OuterPosition(tx) => tx
.send(
window
.outer_position()
.map(|p| PhysicalPositionWrapper(p).into())
.map_err(|_| Error::FailedToSendMessage),
)
.unwrap(),
WindowMessage::InnerSize(tx) => tx
.send(PhysicalSizeWrapper(window.inner_size()).into())
.unwrap(),
WindowMessage::OuterSize(tx) => tx
.send(PhysicalSizeWrapper(window.outer_size()).into())
.unwrap(),
WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(),
WindowMessage::IsMaximized(tx) => window_getter!(window, tx, is_maximized),
WindowMessage::CurrentMonitor(tx) => window_getter!(window, tx, current_monitor),
WindowMessage::PrimaryMonitor(tx) => window_getter!(window, tx, primary_monitor),
WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(),
WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(),
WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(),
WindowMessage::AvailableMonitors(tx) => {
tx.send(window.available_monitors().collect()).unwrap()
}
@ -970,16 +1039,16 @@ impl Runtime for Wry {
window.set_always_on_top(always_on_top)
}
WindowMessage::SetSize(size) => {
window.set_inner_size(WrySize::from(size));
window.set_inner_size(SizeWrapper::from(size).0);
}
WindowMessage::SetMinSize(size) => {
window.set_min_inner_size(size.map(WrySize::from));
window.set_min_inner_size(size.map(|s| SizeWrapper::from(s).0));
}
WindowMessage::SetMaxSize(size) => {
window.set_max_inner_size(size.map(WrySize::from));
window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0));
}
WindowMessage::SetPosition(position) => {
window.set_outer_position(WryPosition::from(position))
window.set_outer_position(PositionWrapper::from(position).0)
}
WindowMessage::SetFullscreen(fullscreen) => {
if fullscreen {
@ -1036,7 +1105,7 @@ fn create_webview<M: Params<Runtime = Wry>>(
event_loop: &EventLoopWindowTarget<Message>,
context: DispatcherContext,
pending: PendingWindow<M>,
) -> crate::Result<WebView> {
) -> Result<WebView> {
let PendingWindow {
webview_attributes,
window_builder,
@ -1047,9 +1116,9 @@ fn create_webview<M: Params<Runtime = Wry>>(
..
} = pending;
let window = window_builder.build(event_loop).unwrap();
let window = window_builder.0.build(event_loop).unwrap();
let mut webview_builder = WebViewBuilder::new(window)
.map_err(|e| crate::Error::CreateWebview(Box::new(e)))?
.map_err(|e| Error::CreateWebview(Box::new(e)))?
.with_url(&url)
.unwrap(); // safe to unwrap because we validate the URL beforehand
if let Some(handler) = rpc_handler {
@ -1074,7 +1143,7 @@ fn create_webview<M: Params<Runtime = Wry>>(
webview_builder
.build()
.map_err(|e| crate::Error::CreateWebview(Box::new(e)))
.map_err(|e| Error::CreateWebview(Box::new(e)))
}
/// Create a wry rpc handler from a tauri rpc handler.
@ -1092,7 +1161,7 @@ fn create_rpc_handler<M: Params<Runtime = Wry>>(
},
label: label.clone(),
},
request.into(),
RpcRequestWrapper(request).into(),
);
None
})
@ -1106,7 +1175,7 @@ fn create_file_drop_handler<M: Params<Runtime = Wry>>(
) -> Box<dyn Fn(&Window, WryFileDropEvent) -> bool + 'static> {
Box::new(move |window, event| {
handler(
event.into(),
FileDropEventWrapper(event).into(),
DetachedWindow {
dispatcher: WryDispatcher {
window_id: window.id(),

View File

@ -0,0 +1,3 @@
// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

View File

@ -13,7 +13,5 @@ edition = "2018"
serde = { version = "1.0", features = [ "derive" ] }
serde_json = "1.0"
thiserror = "1.0"
uuid = { version = "0.8.2", features = [ "v4" ] }
tauri-utils = { version = "1.0.0-beta-rc.1", path = "../tauri-utils" }
wry = { git = "https://github.com/tauri-apps/wry", rev = "6bc97aff525644b83a3a00537316c46d7afb985b" }
image = "0.23"
uuid = { version = "0.8.2", features = [ "v4" ] }

View File

@ -1,7 +0,0 @@
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
//! Officially supported webview runtimes.
pub mod wry;

View File

@ -9,7 +9,6 @@ use std::path::PathBuf;
use tauri_utils::assets::Assets;
use uuid::Uuid;
pub mod flavors;
/// Create window and system tray menus.
pub mod menu;
/// Types useful for interacting with a user's monitors.

View File

@ -3,37 +3,17 @@
// SPDX-License-Identifier: MIT
use super::window::dpi::{PhysicalPosition, PhysicalSize};
use serde::Serialize;
/// Monitor descriptor.
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
#[derive(Debug, Clone)]
pub struct Monitor {
pub(crate) name: Option<String>,
pub(crate) size: PhysicalSize<u32>,
pub(crate) position: PhysicalPosition<i32>,
pub(crate) scale_factor: f64,
}
impl Monitor {
/// Returns a human-readable name of the monitor.
/// Returns None if the monitor doesn't exist anymore.
pub fn name(&self) -> Option<&String> {
self.name.as_ref()
}
/// Returns the monitor's resolution.
pub fn size(&self) -> &PhysicalSize<u32> {
&self.size
}
/// Returns the top-left corner position of the monitor relative to the larger full screen area.
pub fn position(&self) -> &PhysicalPosition<i32> {
&self.position
}
/// A human-readable name of the monitor.
/// `None` if the monitor doesn't exist anymore.
pub name: Option<String>,
/// The monitor's resolution.
pub size: PhysicalSize<u32>,
/// The top-left corner position of the monitor relative to the larger full screen area.
pub position: PhysicalPosition<i32>,
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
pub fn scale_factor(&self) -> f64 {
self.scale_factor
}
pub scale_factor: f64,
}

View File

@ -39,7 +39,6 @@ pub enum WindowEvent {
/// - Changing the display's resolution.
/// - Changing the display's scale factor (e.g. in Control Panel on Windows).
/// - Moving the window to a display with a different scale factor.
#[non_exhaustive]
ScaleFactorChanged {
/// The new scale factor.
scale_factor: f64,

View File

@ -25,6 +25,7 @@ once_cell = "1.7.2"
tauri-runtime = { version = "0.0.0", path = "../tauri-runtime" }
tauri-macros = { version = "1.0.0-beta-rc.1", path = "../tauri-macros" }
tauri-utils = { version = "1.0.0-beta-rc.1", path = "../tauri-utils" }
tauri-runtime-wry = { version = "0.0.0", path = "../tauri-runtime-wry", optional = true }
rand = "0.8"
reqwest = { version = "0.11", features = [ "json", "multipart" ] }
tempfile = "3"
@ -64,6 +65,8 @@ tokio-test = "0.4.1"
mockito = "0.30"
[features]
default = ["wry"]
wry = ["tauri-runtime-wry"]
cli = [ "clap" ]
custom-protocol = [ "tauri-macros/custom-protocol" ]
api-all = [ "notification-all", "global-shortcut-all", "updater" ]

View File

@ -9,7 +9,6 @@ use crate::{
manager::{Args, WindowManager},
plugin::{Plugin, PluginStore},
runtime::{
flavors::wry::Wry,
menu::{Menu, MenuId, SystemTrayMenuItem},
tag::Tag,
webview::{CustomProtocol, WebviewAttributes, WindowBuilder},
@ -511,7 +510,15 @@ fn get_menu_ids<I: MenuId>(items: &[SystemTrayMenuItem<I>]) -> HashMap<u32, I> {
}
/// Make `Wry` the default `Runtime` for `Builder`
impl<A: Assets> Default for Builder<String, String, String, String, A, Wry> {
#[cfg(feature = "wry")]
impl<A: Assets> Default for Builder<String, String, String, String, A, crate::Wry> {
fn default() -> Self {
Self::new()
}
}
#[cfg(not(feature = "wry"))]
impl<A: Assets, R: Runtime> Default for Builder<String, String, String, String, A, R> {
fn default() -> Self {
Self::new()
}

View File

@ -36,6 +36,9 @@ mod state;
#[cfg(feature = "updater")]
pub mod updater;
#[cfg(feature = "wry")]
pub use tauri_runtime_wry::Wry;
/// `Result<T, ::tauri::Error>`
pub type Result<T> = std::result::Result<T, Error>;
@ -59,9 +62,7 @@ pub use {
PageLoadPayload, SetupHook,
},
self::runtime::{
flavors::wry::Wry,
menu::{CustomMenuItem, Menu, MenuId, MenuItem, SystemTrayMenuItem},
monitor::Monitor,
tag::{Tag, TagRef},
webview::{WebviewAttributes, WindowBuilder},
window::{
@ -71,7 +72,7 @@ pub use {
Params,
},
self::state::{State, StateManager},
self::window::{MenuEvent, Window},
self::window::{MenuEvent, Monitor, Window},
tauri_utils::platform,
};

View File

@ -453,7 +453,7 @@ impl<P: Params> WindowManager<P> {
#[cfg(test)]
mod test {
use super::{Args, WindowManager};
use crate::{generate_context, plugin::PluginStore, runtime::flavors::wry::Wry, StateManager};
use crate::{generate_context, plugin::PluginStore, StateManager, Wry};
#[test]
fn check_get_url() {

View File

@ -9,7 +9,7 @@ use crate::{
manager::WindowManager,
runtime::{
menu::MenuId,
monitor::Monitor,
monitor::Monitor as RuntimeMonitor,
tag::{TagRef, ToJsString},
webview::{InvokePayload, WebviewAttributes, WindowBuilder},
window::{
@ -44,6 +44,50 @@ impl<I: MenuId> MenuEvent<I> {
}
}
/// Monitor descriptor.
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Monitor {
pub(crate) name: Option<String>,
pub(crate) size: PhysicalSize<u32>,
pub(crate) position: PhysicalPosition<i32>,
pub(crate) scale_factor: f64,
}
impl From<RuntimeMonitor> for Monitor {
fn from(monitor: RuntimeMonitor) -> Self {
Self {
name: monitor.name,
size: monitor.size,
position: monitor.position,
scale_factor: monitor.scale_factor,
}
}
}
impl Monitor {
/// Returns a human-readable name of the monitor.
/// Returns None if the monitor doesn't exist anymore.
pub fn name(&self) -> Option<&String> {
self.name.as_ref()
}
/// Returns the monitor's resolution.
pub fn size(&self) -> &PhysicalSize<u32> {
&self.size
}
/// Returns the top-left corner position of the monitor relative to the larger full screen area.
pub fn position(&self) -> &PhysicalPosition<i32> {
&self.position
}
/// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
pub fn scale_factor(&self) -> f64 {
self.scale_factor
}
}
/// A webview window managed by Tauri.
///
/// This type also implements [`Manager`] which allows you to manage other windows attached to
@ -316,14 +360,24 @@ impl<P: Params> Window<P> {
///
/// Returns None if current monitor can't be detected.
pub fn current_monitor(&self) -> crate::Result<Option<Monitor>> {
self.window.dispatcher.current_monitor().map_err(Into::into)
self
.window
.dispatcher
.current_monitor()
.map(|m| m.map(Into::into))
.map_err(Into::into)
}
/// Returns the primary monitor of the system.
///
/// Returns None if it can't identify any monitor as a primary one.
pub fn primary_monitor(&self) -> crate::Result<Option<Monitor>> {
self.window.dispatcher.primary_monitor().map_err(Into::into)
self
.window
.dispatcher
.primary_monitor()
.map(|m| m.map(Into::into))
.map_err(Into::into)
}
/// Returns the list of all the monitors available on the system.
@ -332,6 +386,7 @@ impl<P: Params> Window<P> {
.window
.dispatcher
.available_monitors()
.map(|m| m.into_iter().map(Into::into).collect())
.map_err(Into::into)
}