Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,10 @@ French strings complete.
- `src/preferences.rs`: `preferences.json` and the commands that read and
write it
- `src/paths.rs`: the Colony folder layout
- `src/window_state.rs`: remembers the window position between runs
- `src/window_state.rs`: opens the main window on the chosen layout and
remembers its position between runs
- `src/migrate.rs`: copies the settings of versions before the Colony layout
and opens the preferences store
- `src/linux_display.rs`: turns off WebKitGTK's DMA-BUF renderer and
accelerated compositing under Wayland, where they fail on some drivers
- `src/i18n.rs`: tests that hold the two locale files to the same keys
Expand Down Expand Up @@ -233,21 +235,24 @@ roaming) application folders:
|---|---|---|
| Preferences | stored | `preferences/preferences.json` in the settings folder: theme, accent, text size, accessibility, language and startup layout, saved as soon as they change. A setting with a bad value falls back to its default; a theme orCAL does not ship becomes Gruvbox dark, Colony's fallback, and an unknown accent becomes the theme's own. A file that orCAL reads but that is not a JSON object is moved to `preferences.json.bak` and orCAL starts from the defaults. A file it cannot read (permissions, a lock) or cannot move aside is left untouched: orCAL starts from the defaults and saves nothing over it until the next launch |
| Window position | stored | `window-position.json` in the settings folder, so the window opens where you left it. On Wayland the compositor decides where windows open |
| Web view profile | stored | the web view's own storage and cache, in `webview/` in the data folder on Linux and Windows, and in the system's WebKit location on macOS. orCAL keeps nothing of its own there once the old theme below has been imported |
| Migration marker | stored | `.migrated` in the settings folder, written by the first launch of a version with the Colony layout. It records where the settings of older versions were looked for, so the copy below runs only once |
| Web view profile | stored | the web view's own storage and cache. orCAL keeps nothing of its own there once the old theme below has been imported, so it is cache: `webview/` in the cache folder on Linux and Windows. On macOS, where the web view cannot be given a folder, it uses a non-persistent store kept in memory instead of the system's WebKit folder |
| Expressions and results | neither | kept only in the open window, gone when you close it |

| Folder | Linux | Windows | macOS |
|---|---|---|---|
| Settings | `~/.config/Colony/orCAL/` | `%LOCALAPPDATA%\Colony\orCAL\` | `~/Library/Application Support/Colony/orCAL/` |
| Data | `~/.local/share/Colony/orCAL/` | `%LOCALAPPDATA%\Colony\orCAL\` | `~/Library/Application Support/Colony/orCAL/` |
| Data (not used) | `~/.local/share/Colony/orCAL/` | `%LOCALAPPDATA%\Colony\orCAL\` | `~/Library/Application Support/Colony/orCAL/` |
| Cache | `~/.cache/Colony/orCAL/` | `%LOCALAPPDATA%\Colony\orCAL\cache\` | `~/Library/Caches/Colony/orCAL/` (not used) |

Preferences > About shows the exact folders on your machine.

Versions before the Colony layout kept these in `com.orcal.app` folders. The
first launch of a newer version copies the window position over and imports
the theme from the old web view storage; the launch after that switches to the
new web view folder. The old `com.orcal.app` folders are left in place and can
be deleted by hand.
new web view profile. The old `com.orcal.app` folders are left in place and can
be deleted by hand, and so can the `webview/` folder that 0.4.0 kept in the
data folder on Linux and Windows.

The interface is drawn by the operating system's web view (Microsoft Edge
WebView2 on Windows, WebKit on macOS and Linux), which follows its vendor's own
Expand Down
64 changes: 6 additions & 58 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ mod paths;
mod preferences;
mod window_state;

use preferences::{Preferences, Store};
use tauri::{App, LogicalSize, Manager, WebviewUrl, WebviewWindow, WebviewWindowBuilder};
use tauri::Manager;

fn main() {
// Before anything else, and without opening a window: the release
Expand All @@ -30,27 +29,13 @@ fn main() {
let config_dir = paths::config_dir()
.inspect_err(|error| log::warn!("orCAL cannot keep its settings: {error}"))
.ok();
let legacy_dir = migrate::legacy_config_dir();
if let (Some(config), Some(legacy)) = (&config_dir, &legacy_dir) {
if let Err(error) = migrate::run(legacy, config) {
log::warn!("settings from before the Colony layout not copied: {error}");
}
}

let store = Store::open(config_dir.as_deref().map(preferences::file_in));
let mut preferences = store.get();
// Every build before the Colony layout created its config folder on
// first launch, so without one there is no old webview profile and
// no theme in it to import: start on the new profile straight away.
if !preferences.legacy_storage_imported && legacy_dir.is_some_and(|dir| !dir.exists()) {
preferences.legacy_storage_imported = true;
if let Err(error) = store.set(preferences.clone()) {
log::warn!("preferences not saved: {error}");
}
}
let (store, preferences) = migrate::open_store(
config_dir.as_deref(),
migrate::legacy_config_dir().as_deref(),
);
app.manage(store);

let window = open_main_window(app, &preferences)?;
let window = window_state::open_main_window(app, &preferences)?;
window_state::attach(&window, config_dir.as_deref());
Ok(())
})
Expand All @@ -64,43 +49,6 @@ fn main() {
.expect("error while running tauri application");
}

/// Opens the main window, described in tauri.conf.json (where it is not
/// created at startup), on the layout chosen in Preferences.
fn open_main_window(app: &App, preferences: &Preferences) -> tauri::Result<WebviewWindow> {
let mut config = app
.config()
.app
.windows
.iter()
.find(|window| window.label == "main")
.cloned()
.expect("tauri.conf.json describes the main window");
let layout = preferences.startup_layout;
config.url = WebviewUrl::App(layout.page().into());
(config.width, config.height) = layout.size();

let mut builder = WebviewWindowBuilder::from_config(app.handle(), &config)?;
// The webview profile moves to Colony/orCAL only once the theme the old
// builds kept in its localStorage has been imported (common/prefs.js):
// until then the old profile, Tauri's default, is the only place it is.
// macOS WKWebView has no data directory and keeps its default location.
if preferences.legacy_storage_imported {
match paths::data_dir() {
Ok(data) => builder = builder.data_directory(data.join("webview")),
Err(error) => log::warn!("the webview keeps its default profile: {error}"),
}
}
let window = builder.build()?;
// A floating window manager can map the window before the builder's size
// reaches it (XWayland only saw a 10x10 hint) and pick its own size;
// asking again once the window exists gives the layout's size.
let (width, height) = layout.size();
if let Err(error) = window.set_size(LogicalSize::new(width, height)) {
log::warn!("the window keeps the size the window manager chose: {error}");
}
Ok(window)
}

/// Whether the command line, without the program name, asks for the version.
fn asks_for_version(args: impl IntoIterator<Item = impl AsRef<str>>) -> bool {
args.into_iter()
Expand Down
43 changes: 43 additions & 0 deletions src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use crate::preferences::{self, Preferences, Store};
use crate::{paths, window_state};

/// Tauri's bundle identifier, the folder name of the pre-Colony layout.
Expand Down Expand Up @@ -49,6 +50,30 @@ pub fn run(legacy: &Path, config: &Path) -> io::Result<()> {
)
}

/// Bring over what the pre-Colony builds kept in `legacy`, then open the
/// preferences store in `config` (`None`: settings last for the session). The
/// preferences returned are the ones to open the window on.
pub fn open_store(config: Option<&Path>, legacy: Option<&Path>) -> (Store, Preferences) {
if let (Some(config), Some(legacy)) = (config, legacy) {
if let Err(error) = run(legacy, config) {
log::warn!("settings from before the Colony layout not copied: {error}");
}
}

let store = Store::open(config.map(preferences::file_in));
let mut preferences = store.get();
// Every build before the Colony layout created its config folder on first
// launch, so without one there is no old webview profile and no theme in
// it to import: start on the new profile straight away.
if !preferences.legacy_storage_imported && legacy.is_some_and(|dir| !dir.exists()) {
preferences.legacy_storage_imported = true;
if let Err(error) = store.set(preferences.clone()) {
log::warn!("preferences not saved: {error}");
}
}
(store, preferences)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -126,4 +151,22 @@ mod tests {
assert!(legacy.join("orcal").join(window_state::FILE).exists());
fs::remove_dir_all(root).unwrap();
}

#[test]
fn the_old_profile_is_kept_only_while_an_old_folder_exists() {
let root = temp_dir("migrate-store");
let config = root.join("new");
fs::create_dir_all(&config).unwrap();

let legacy = root.join(LEGACY_IDENTIFIER);
fs::create_dir_all(&legacy).unwrap();
let (_, preferences) = open_store(Some(&config), Some(&legacy));
assert!(!preferences.legacy_storage_imported);

fs::remove_dir_all(&legacy).unwrap();
let (store, preferences) = open_store(Some(&config), Some(&legacy));
assert!(preferences.legacy_storage_imported);
assert!(store.get().legacy_storage_imported);
fs::remove_dir_all(root).unwrap();
}
}
Loading
Loading