Add Linux system window decorations setting

Expose a per-user setting to toggle system window decorations on Linux
and apply it to the UI and window behavior.

- Add a SettingsScreen option (Linux-only) to toggle "System window decorations" and bind it to the app store.
- Track the preference in app store with persistent localStorage key and getter/setter (setSystemDecorations) that updates the Tauri window decorations via getCurrentWindow().setDecorations().
- Respect the setting when rendering the main App.svelte by disabling rounded corners and custom Linux window border when system decorations are enabled. This change is needed to let Linux users choose native title bar/window chrome for better integration with their desktop environment.
This commit is contained in:
Tristan Michael 2026-04-14 05:58:17 -07:00
parent 31af983640
commit 34d7e8b17d
3 changed files with 38 additions and 3 deletions

View file

@ -14,11 +14,11 @@
</script> </script>
<div class={app.isDark ? "dark" : ""} data-theme={app.currentTheme ?? ""}> <div class={app.isDark ? "dark" : ""} data-theme={app.currentTheme ?? ""}>
<div class="h-screen w-screen" class:p-2={isLinux}> <div class="h-screen w-screen" class:p-2={isLinux && !app.systemDecorations}>
<div <div
class="relative h-full w-full overflow-hidden bg-surface-light text-text-light dark:bg-surface-dark dark:text-text-dark" class="relative h-full w-full overflow-hidden bg-surface-light text-text-light dark:bg-surface-dark dark:text-text-dark"
class:rounded-xl={isLinux} class:rounded-xl={isLinux && !app.systemDecorations}
class:linux-window-border={isLinux} class:linux-window-border={isLinux && !app.systemDecorations}
style="container-type: inline-size" style="container-type: inline-size"
> >
{#if app.error} {#if app.error}

View file

@ -1,8 +1,11 @@
<script lang="ts"> <script lang="ts">
import { invoke } from "@tauri-apps/api/core"; import { invoke } from "@tauri-apps/api/core";
import { platform } from "@tauri-apps/plugin-os";
import { app } from "../stores/app.svelte"; import { app } from "../stores/app.svelte";
import ConfirmDialog from "../components/ConfirmDialog.svelte"; import ConfirmDialog from "../components/ConfirmDialog.svelte";
const isLinux = platform() === "linux";
let { onclose, workspaceId, ondelete }: { onclose?: () => void; workspaceId: string; ondelete?: (id: string) => void } = $props(); let { onclose, workspaceId, ondelete }: { onclose?: () => void; workspaceId: string; ondelete?: (id: string) => void } = $props();
let ws = $derived(app.config?.workspaces[workspaceId]); let ws = $derived(app.config?.workspaces[workspaceId]);
@ -264,6 +267,24 @@
</select> </select>
</section> </section>
{#if isLinux}
<!-- Window decorations (Linux only) -->
<section class="mt-6">
<label class="flex cursor-pointer items-center justify-between gap-3">
<div>
<p class="text-sm font-medium">System window decorations</p>
<p class="text-xs opacity-50">Use the system title bar instead of the custom border</p>
</div>
<input
type="checkbox"
checked={app.systemDecorations}
onchange={(e) => app.setSystemDecorations((e.target as HTMLInputElement).checked)}
class="h-4 w-4 cursor-pointer accent-primary"
/>
</label>
</section>
{/if}
<p class="mt-8 text-center text-xs opacity-30">Tauri v2 + Svelte</p> <p class="mt-8 text-center text-xs opacity-30">Tauri v2 + Svelte</p>
</main> </main>

View file

@ -18,6 +18,10 @@ listen("fs-changed", () => {
// ── Reactive state ─────────────────────────────────────────────────── // ── Reactive state ───────────────────────────────────────────────────
const LS_DECORATIONS_KEY = "systemDecorations";
let systemDecorations = $state(localStorage.getItem(LS_DECORATIONS_KEY) === "true");
if (systemDecorations) getCurrentWindow().setDecorations(true);
let screen = $state<Screen>("setup"); let screen = $state<Screen>("setup");
let config = $state<AppConfig | null>(null); let config = $state<AppConfig | null>(null);
let lists = $state<TaskList[]>([]); let lists = $state<TaskList[]>([]);
@ -429,6 +433,12 @@ async function setSyncIntervalUnfocused(secs: number | null) {
} }
} }
function setSystemDecorations(value: boolean) {
systemDecorations = value;
localStorage.setItem(LS_DECORATIONS_KEY, String(value));
getCurrentWindow().setDecorations(value);
}
async function setTheme(theme: string | null) { async function setTheme(theme: string | null) {
if (!config?.current_workspace) return; if (!config?.current_workspace) return;
try { try {
@ -549,6 +559,9 @@ export const app = {
get lastSyncResult() { get lastSyncResult() {
return lastSyncResult; return lastSyncResult;
}, },
get systemDecorations() {
return systemDecorations;
},
get error() { get error() {
return error; return error;
}, },
@ -582,6 +595,7 @@ export const app = {
stopAutoSync, stopAutoSync,
setSyncInterval, setSyncInterval,
setSyncIntervalUnfocused, setSyncIntervalUnfocused,
setSystemDecorations,
setTheme, setTheme,
addWebdavWorkspace, addWebdavWorkspace,
forgetMissingWorkspace, forgetMissingWorkspace,