feat(window-state): add flags to control what is saved/restored

pull/104/head
amrbashir 3 years ago
parent 4ff7843581
commit 47e85ad06d
No known key found for this signature in database
GPG Key ID: BBD7A47A2003FF33

13
Cargo.lock generated

@ -235,7 +235,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [ dependencies = [
"hermit-abi 0.1.19", "hermit-abi 0.1.19",
"libc", "libc",
"winapi 0.3.9", "winapi",
] ]
[[package]] [[package]]
@ -610,7 +610,7 @@ checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
dependencies = [ dependencies = [
"atty", "atty",
"lazy_static", "lazy_static",
"winapi 0.3.9", "winapi",
] ]
[[package]] [[package]]
@ -2458,7 +2458,7 @@ checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bitflags", "bitflags",
"cfg-if 1.0.0", "cfg-if",
"libc", "libc",
"memoffset", "memoffset",
"pin-utils", "pin-utils",
@ -3032,7 +3032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cfg-if 1.0.0", "cfg-if",
"libc", "libc",
"log", "log",
"wepoll-ffi", "wepoll-ffi",
@ -4435,6 +4435,7 @@ name = "tauri-plugin-window-state"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bincode", "bincode",
"bitflags",
"log", "log",
"serde", "serde",
"serde_json", "serde_json",
@ -4869,7 +4870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d"
dependencies = [ dependencies = [
"tempfile", "tempfile",
"winapi 0.3.9", "winapi",
] ]
[[package]] [[package]]
@ -5598,7 +5599,7 @@ dependencies = [
"static_assertions", "static_assertions",
"tracing", "tracing",
"uds_windows", "uds_windows",
"winapi 0.3.9", "winapi",
"zbus_macros", "zbus_macros",
"zbus_names", "zbus_names",
"zvariant", "zvariant",

@ -15,4 +15,5 @@ serde_json.workspace = true
tauri.workspace = true tauri.workspace = true
log.workspace = true log.workspace = true
thiserror.workspace = true thiserror.workspace = true
bincode = "1.3" bincode = "1.3"
bitflags = "1"

@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use bitflags::bitflags;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin}, plugin::{Builder as PluginBuilder, TauriPlugin},
@ -30,25 +31,25 @@ pub enum Error {
Bincode(#[from] Box<bincode::ErrorKind>), Bincode(#[from] Box<bincode::ErrorKind>),
} }
/// Defines how the window visibility should be restored. pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ShowMode { bitflags! {
/// The window will always be shown, regardless of what the last stored state was. pub struct StateFlags: u32 {
Always, const SIZE = 1 << 0;
/// The window will be automatically shown if the last stored state for visibility was `true`. const POSITION = 1 << 1;
LastSaved, const MAXIMIZED = 1 << 2;
/// The window will not be automatically shown by this plugin. const VISIBLE = 1 << 3;
Never, const DECORATIONS = 1 << 4;
const FULLSCREEN = 1 << 5;
}
} }
impl Default for ShowMode { impl Default for StateFlags {
fn default() -> Self { fn default() -> Self {
Self::LastSaved Self::all()
} }
} }
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Default, Deserialize, Serialize)] #[derive(Debug, Default, Deserialize, Serialize)]
struct WindowMetadata { struct WindowMetadata {
width: f64, width: f64,
@ -86,50 +87,86 @@ impl<R: Runtime> AppHandleExt for tauri::AppHandle<R> {
} }
pub trait WindowExt { pub trait WindowExt {
fn restore_state(&self, show_mode: ShowMode) -> tauri::Result<()>; fn restore_state(&self, flags: StateFlags) -> tauri::Result<()>;
} }
impl<R: Runtime> WindowExt for Window<R> { impl<R: Runtime> WindowExt for Window<R> {
fn restore_state(&self, show_mode: ShowMode) -> tauri::Result<()> { fn restore_state(&self, flags: StateFlags) -> tauri::Result<()> {
let cache = self.state::<WindowStateCache>(); let cache = self.state::<WindowStateCache>();
let mut c = cache.0.lock().unwrap(); let mut c = cache.0.lock().unwrap();
let mut should_show = true; let mut should_show = true;
if let Some(state) = c.get(self.label()) { if let Some(state) = c.get(self.label()) {
self.set_decorations(state.decorated)?; if flags.contains(StateFlags::DECORATIONS) {
self.set_decorations(state.decorated)?;
self.set_size(LogicalSize { }
width: state.width,
height: state.height, if flags.contains(StateFlags::SIZE) {
})?; self.set_size(LogicalSize {
width: state.width,
// restore position to saved value if saved monitor exists height: state.height,
// otherwise, let the OS decide where to place the window })?;
for m in self.available_monitors()? { }
if m.contains((state.x, state.y).into()) {
self.set_position(PhysicalPosition { if flags.contains(StateFlags::POSITION) {
x: state.x, // restore position to saved value if saved monitor exists
y: state.y, // otherwise, let the OS decide where to place the window
})?; for m in self.available_monitors()? {
if m.contains((state.x, state.y).into()) {
self.set_position(PhysicalPosition {
x: state.x,
y: state.y,
})?;
}
} }
} }
if state.maximized { if flags.contains(StateFlags::MAXIMIZED) && state.maximized {
self.maximize()?; self.maximize()?;
} }
self.set_fullscreen(state.fullscreen)?;
if flags.contains(StateFlags::FULLSCREEN) {
self.set_fullscreen(state.fullscreen)?;
}
should_show = state.visible; should_show = state.visible;
} else { } else {
let scale_factor = self let LogicalSize { width, height } = match flags.contains(StateFlags::SIZE) {
.current_monitor()? true => {
.map(|m| m.scale_factor()) let scale_factor = self
.unwrap_or(1.); .current_monitor()?
let LogicalSize { width, height } = self.inner_size()?.to_logical(scale_factor); .map(|m| m.scale_factor())
let PhysicalPosition { x, y } = self.outer_position()?; .unwrap_or(1.);
let maximized = self.is_maximized().unwrap_or(false); self.inner_size()?.to_logical(scale_factor)
let visible = self.is_visible().unwrap_or(true); }
let decorated = self.is_decorated().unwrap_or(true); false => (0, 0).into(),
let fullscreen = self.is_fullscreen().unwrap_or(false); };
let PhysicalPosition { x, y } = match flags.contains(StateFlags::POSITION) {
true => self.outer_position()?,
false => (0, 0).into(),
};
let maximized = match flags.contains(StateFlags::MAXIMIZED) {
true => self.is_maximized().unwrap_or(false),
false => false,
};
let visible = match flags.contains(StateFlags::VISIBLE) {
true => self.is_visible().unwrap_or(true),
false => true,
};
let decorated = match flags.contains(StateFlags::DECORATIONS) {
true => self.is_visible().unwrap_or(true),
false => true,
};
let fullscreen = match flags.contains(StateFlags::FULLSCREEN) {
true => self.is_fullscreen().unwrap_or(false),
false => false,
};
c.insert( c.insert(
self.label().into(), self.label().into(),
WindowMetadata { WindowMetadata {
@ -145,7 +182,7 @@ impl<R: Runtime> WindowExt for Window<R> {
); );
} }
if show_mode == ShowMode::Always || (show_mode == ShowMode::LastSaved && should_show) { if flags.contains(StateFlags::VISIBLE) && should_show {
self.show()?; self.show()?;
self.set_focus()?; self.set_focus()?;
} }
@ -156,17 +193,15 @@ impl<R: Runtime> WindowExt for Window<R> {
#[derive(Default)] #[derive(Default)]
pub struct Builder { pub struct Builder {
show_mode: ShowMode,
denylist: HashSet<String>, denylist: HashSet<String>,
skip_initial_state: HashSet<String>, skip_initial_state: HashSet<String>,
state_flags: StateFlags,
} }
impl Builder { impl Builder {
/// Sets how the window visibility should be restored. /// Sets the state flags to control what state gets restored and saved.
/// pub fn with_state_flags(mut self, flags: StateFlags) -> Self {
/// The default is [`ShowMode::LastSaved`] self.state_flags = flags;
pub fn with_show_mode(mut self, show_mode: ShowMode) -> Self {
self.show_mode = show_mode;
self self
} }
@ -212,59 +247,84 @@ impl Builder {
} }
if !self.skip_initial_state.contains(window.label()) { if !self.skip_initial_state.contains(window.label()) {
let _ = window.restore_state(self.show_mode); let _ = window.restore_state(self.state_flags);
} }
let cache = window.state::<WindowStateCache>(); let cache = window.state::<WindowStateCache>();
let cache = cache.0.clone(); let cache = cache.0.clone();
let label = window.label().to_string(); let label = window.label().to_string();
let window_clone = window.clone(); let window_clone = window.clone();
let flags = self.state_flags.clone();
window.on_window_event(move |e| match e { window.on_window_event(move |e| match e {
WindowEvent::Moved(position) => { WindowEvent::Moved(position) => {
let mut c = cache.lock().unwrap(); let mut c = cache.lock().unwrap();
if let Some(state) = c.get_mut(&label) { if let Some(state) = c.get_mut(&label) {
let is_maximized = window_clone.is_maximized().unwrap_or(false); if flags.intersects(StateFlags::MAXIMIZED | StateFlags::POSITION) {
state.maximized = is_maximized; let is_maximized = window_clone.is_maximized().unwrap_or(false);
if let Some(monitor) = window_clone.current_monitor().unwrap() { if flags.contains(StateFlags::MAXIMIZED) {
let monitor_position = monitor.position(); state.maximized = is_maximized;
// save only window positions that are inside the current monitor }
if position.x > monitor_position.x
&& position.y > monitor_position.y if flags.contains(StateFlags::POSITION) {
&& !is_maximized if let Some(monitor) = window_clone.current_monitor().unwrap() {
{ let monitor_position = monitor.position();
state.x = position.x; // save only window positions that are inside the current monitor
state.y = position.y; if position.x > monitor_position.x
}; && position.y > monitor_position.y
}; && !is_maximized
{
state.x = position.x;
state.y = position.y;
}
}
}
}
} }
} }
WindowEvent::Resized(size) => { WindowEvent::Resized(size) => {
let scale_factor = window_clone
.current_monitor()
.ok()
.map(|m| m.map(|m| m.scale_factor()).unwrap_or(1.))
.unwrap_or(1.);
let size = size.to_logical(scale_factor);
let mut c = cache.lock().unwrap(); let mut c = cache.lock().unwrap();
if let Some(state) = c.get_mut(&label) { if let Some(state) = c.get_mut(&label) {
let is_maximized = window_clone.is_maximized().unwrap_or(false); let is_maximized =
let is_fullscreen = window_clone.is_fullscreen().unwrap_or(false); match flags.intersects(StateFlags::MAXIMIZED | StateFlags::SIZE) {
state.decorated = window_clone.is_decorated().unwrap_or(true); true => window_clone.is_maximized().unwrap_or(false),
state.maximized = is_maximized; false => false,
state.fullscreen = is_fullscreen; };
// It doesn't make sense to save a window with 0 height or width if flags.contains(StateFlags::MAXIMIZED) {
if size.width > 0. && size.height > 0. && !is_maximized { state.maximized = is_maximized;
state.width = size.width; }
state.height = size.height;
if flags.contains(StateFlags::FULLSCREEN) {
state.fullscreen = window_clone.is_fullscreen().unwrap_or(false);
}
if flags.contains(StateFlags::DECORATIONS) {
state.decorated = window_clone.is_decorated().unwrap_or(true);
}
if flags.contains(StateFlags::SIZE) {
let scale_factor = window_clone
.current_monitor()
.ok()
.map(|m| m.map(|m| m.scale_factor()).unwrap_or(1.))
.unwrap_or(1.);
let size = size.to_logical(scale_factor);
// It doesn't make sense to save a window with 0 height or width
if size.width > 0. && size.height > 0. && !is_maximized {
state.width = size.width;
state.height = size.height;
}
} }
} }
} }
WindowEvent::CloseRequested { .. } => { WindowEvent::CloseRequested { .. } => {
let mut c = cache.lock().unwrap(); let mut c = cache.lock().unwrap();
if let Some(state) = c.get_mut(&label) { if let Some(state) = c.get_mut(&label) {
state.visible = window_clone.is_visible().unwrap_or(true); if flags.contains(StateFlags::VISIBLE) {
state.visible = window_clone.is_visible().unwrap_or(true);
}
} }
} }
_ => {} _ => {}

Loading…
Cancel
Save