mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-04-29 12:06:01 +02:00
* feat(window-state): add js api, closes #254 * symlink tsconfig.json * update symlink * Update plugins/window-state/package.json Co-authored-by: Fabian-Lars <fabianlars@fabianlars.de> * Update Cargo.toml * move to cmd.rs * Update plugins/window-state/guest-js/index.ts --------- Co-authored-by: Fabian-Lars <fabianlars@fabianlars.de>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "tauri-plugin-window-state"
|
||||
version = "0.1.0"
|
||||
description = "Save window positions and sizse and restore them when the app is reopened."
|
||||
description = "Save window positions and sizes and restore them when the app is reopened."
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
@@ -16,4 +16,4 @@ tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
bincode = "1.3"
|
||||
bitflags = "2"
|
||||
bitflags = "2"
|
||||
|
||||
@@ -21,6 +21,18 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
|
||||
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
|
||||
```
|
||||
|
||||
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
||||
|
||||
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
|
||||
|
||||
```sh
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-window-state
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-window-state
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-window-state
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
First you need to register the core plugin with Tauri:
|
||||
@@ -47,6 +59,14 @@ use tauri_plugin_window_state::{AppHandleExt, StateFlags};
|
||||
app.save_window_state(StateFlags::all()); // will save the state of all open windows to disk
|
||||
```
|
||||
|
||||
or through Javascript
|
||||
|
||||
```javascript
|
||||
import { saveWindowState, StateFlags } from "tauri-plugin-window-state-api";
|
||||
|
||||
saveWindowState(StateFlags.ALL);
|
||||
```
|
||||
|
||||
To manually restore a windows state from disk you can call the `restore_state()` method exposed by the `WindowExt` trait:
|
||||
|
||||
```rust
|
||||
@@ -56,6 +76,14 @@ use tauri_plugin_window_state::{WindowExt, StateFlags};
|
||||
window.restore_state(StateFlags::all()); // will restore the windows state from disk
|
||||
```
|
||||
|
||||
or through Javascript
|
||||
|
||||
```javascript
|
||||
import { restoreStateCurrent, StateFlags } from "tauri-plugin-window-state-api";
|
||||
|
||||
restoreStateCurrent(StateFlags.ALL);
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
PRs accepted. Please make sure to read the Contributing Guide before making a pull request.
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
import { WindowLabel, getCurrent } from "@tauri-apps/api/window";
|
||||
|
||||
export enum StateFlags {
|
||||
SIZE = 1 << 0,
|
||||
POSITION = 1 << 1,
|
||||
MAXIMIZED = 1 << 2,
|
||||
VISIBLE = 1 << 3,
|
||||
DECORATIONS = 1 << 4,
|
||||
FULLSCREEN = 1 << 5,
|
||||
ALL = SIZE | POSITION | MAXIMIZED | VISIBLE | DECORATIONS | FULLSCREEN,
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the state of all open windows to disk.
|
||||
*/
|
||||
async function saveWindowState(flags: StateFlags) {
|
||||
invoke("plugin:window-state|js_save_window_state", { flags });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the state for the specified window from disk.
|
||||
*/
|
||||
async function restoreState(label: WindowLabel, flags: StateFlags) {
|
||||
invoke("plugin:window-state|js_restore_state", { label, flags });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the state for the current window from disk.
|
||||
*/
|
||||
async function restoreStateCurrent(flags: StateFlags) {
|
||||
restoreState(getCurrent().label, flags);
|
||||
}
|
||||
|
||||
export { restoreState, restoreStateCurrent, saveWindowState };
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "tauri-plugin-window-state-api",
|
||||
"version": "0.1.0",
|
||||
"description": "Save window positions and sizes and restore them when the app is reopened.",
|
||||
"license": "MIT or APACHE-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
],
|
||||
"type": "module",
|
||||
"browser": "dist-js/index.min.js",
|
||||
"module": "dist-js/index.mjs",
|
||||
"types": "dist-js/index.d.ts",
|
||||
"exports": {
|
||||
"import": "./dist-js/index.mjs",
|
||||
"types": "./dist-js/index.d.ts",
|
||||
"browser": "./dist-js/index.min.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup -c"
|
||||
},
|
||||
"files": [
|
||||
"dist-js",
|
||||
"!dist-js/**/*.map",
|
||||
"README.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { readFileSync } from "fs";
|
||||
|
||||
import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
use crate::{AppHandleExt, StateFlags, WindowExt};
|
||||
use tauri::{command, AppHandle, Manager, Runtime};
|
||||
|
||||
#[command]
|
||||
pub async fn save_window_state<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
flags: u32,
|
||||
) -> std::result::Result<(), String> {
|
||||
let flags = StateFlags::from_bits(flags)
|
||||
.ok_or_else(|| format!("Invalid state flags bits: {}", flags))?;
|
||||
app.save_window_state(flags).map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub async fn restore_state<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
label: String,
|
||||
flags: u32,
|
||||
) -> std::result::Result<(), String> {
|
||||
let flags = StateFlags::from_bits(flags)
|
||||
.ok_or_else(|| format!("Invalid state flags bits: {}", flags))?;
|
||||
app.get_window(&label)
|
||||
.ok_or_else(|| format!("Couldn't find window with label: {}", label))?
|
||||
.restore_state(flags)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -17,6 +17,8 @@ use std::{
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
mod cmd;
|
||||
|
||||
pub const STATE_FILENAME: &str = ".window-state";
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@@ -34,7 +36,7 @@ pub enum Error {
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StateFlags: u32 {
|
||||
const SIZE = 1 << 0;
|
||||
const POSITION = 1 << 1;
|
||||
@@ -51,7 +53,7 @@ impl Default for StateFlags {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
|
||||
struct WindowState {
|
||||
width: f64,
|
||||
height: f64,
|
||||
@@ -65,6 +67,7 @@ struct WindowState {
|
||||
|
||||
struct WindowStateCache(Arc<Mutex<HashMap<String, WindowState>>>);
|
||||
pub trait AppHandleExt {
|
||||
/// Saves all open windows state to disk
|
||||
fn save_window_state(&self, flags: StateFlags) -> Result<()>;
|
||||
}
|
||||
|
||||
@@ -94,6 +97,7 @@ impl<R: Runtime> AppHandleExt for tauri::AppHandle<R> {
|
||||
}
|
||||
|
||||
pub trait WindowExt {
|
||||
/// Restores this window state from disk
|
||||
fn restore_state(&self, flags: StateFlags) -> tauri::Result<()>;
|
||||
}
|
||||
|
||||
@@ -101,9 +105,15 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
fn restore_state(&self, flags: StateFlags) -> tauri::Result<()> {
|
||||
let cache = self.state::<WindowStateCache>();
|
||||
let mut c = cache.0.lock().unwrap();
|
||||
|
||||
let mut should_show = true;
|
||||
|
||||
if let Some(state) = c.get(self.label()) {
|
||||
// avoid restoring the default zeroed state
|
||||
if *state == WindowState::default() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if flags.contains(StateFlags::DECORATIONS) {
|
||||
self.set_decorations(state.decorated)?;
|
||||
}
|
||||
@@ -270,6 +280,10 @@ impl Builder {
|
||||
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
|
||||
let flags = self.state_flags;
|
||||
PluginBuilder::new("window-state")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
cmd::save_window_state,
|
||||
cmd::restore_state
|
||||
])
|
||||
.setup(|app| {
|
||||
let cache: Arc<Mutex<HashMap<String, WindowState>>> = if let Some(app_dir) =
|
||||
app.path_resolver().app_config_dir()
|
||||
@@ -305,6 +319,17 @@ impl Builder {
|
||||
let label = window.label().to_string();
|
||||
let window_clone = window.clone();
|
||||
let flags = self.state_flags;
|
||||
|
||||
// insert a default state if this window should be tracked and
|
||||
// the disk cache doesn't have a state for it
|
||||
{
|
||||
cache
|
||||
.lock()
|
||||
.unwrap()
|
||||
.entry(label.clone())
|
||||
.or_insert_with(WindowState::default);
|
||||
}
|
||||
|
||||
window.on_window_event(move |e| {
|
||||
if let WindowEvent::CloseRequested { .. } = e {
|
||||
let mut c = cache.lock().unwrap();
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../shared/tsconfig.json
|
||||
Generated
+925
-783
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user