Windows support

This commit is contained in:
sarah committed 2026-10-09 14:30:59 +02:00
1 parent 6b2b35f5da
commit b295db3fb6
9 files changed
+136 -26

No files matched your search

+51 -5
View File
@@ -5,8 +5,10 @@ SaraView/Backend/DefaultThemes/CatppuccinMocha.toml and Frontend/src/Styles/Them
one accent colour (Purple/Mauve) used everywhere, not a mauve+lavender mix.
"""
import os
import shutil
import subprocess
import sys
from dataclasses import asdict, dataclass, field
from pathlib import Path
from typing import Callable, Optional
@@ -45,7 +47,19 @@ AppName = "SaraFem"
BundledFontFamily = "Fixedsys Excelsior"
ActiveFontFamily = BundledFontFamily # set by ApplyAppearance, read by BuildTheme
CacheDir = Path.home() / ".cache" / "SaraFem"
IsWindows = sys.platform == "win32"
# Each system's own per-user folders, like SaraSuite's: ~/.config and ~/.cache
# on Linux; %APPDATA% (settings) and %LOCALAPPDATA% (caches) on Windows.
if IsWindows:
ConfigHome = Path(os.environ.get("APPDATA") or Path.home() / "AppData" / "Roaming")
CacheDir = Path(os.environ.get("LOCALAPPDATA") or Path.home() / "AppData" / "Local") / "SaraFem" / "Cache"
# Where the file tree starts by default: the system drive (C:\), not "/".
DefaultFiletreeRoot = (os.environ.get("SystemDrive") or "C:") + "\\"
else:
ConfigHome = Path(os.environ.get("XDG_CONFIG_HOME") or Path.home() / ".config")
CacheDir = Path(os.environ.get("XDG_CACHE_HOME") or Path.home() / ".cache") / "SaraFem"
DefaultFiletreeRoot = "/"
ThumbnailCacheDir = CacheDir / "Thumbnails"
# Copy/Cut/Paste uses the real OS clipboard (Clipboard.set_files/get_files —
@@ -72,7 +86,7 @@ def GetClipboardMode() -> str:
# Config moved from ~/.config/SaraFem/ into a SaraSuite-wide layout so other
# Sara* programs (SaraTag, SaraView) can eventually read from the same place.
SharedConfigDir = Path.home() / ".config" / "SaraSuite"
SharedConfigDir = ConfigHome / "SaraSuite"
ThemesDir = SharedConfigDir / "Themes"
ConfigDir = SharedConfigDir / "SaraFem"
ConfigPath = ConfigDir / "Config.toml"
@@ -328,7 +342,7 @@ class AppConfig:
# always showing it with a "No devices." placeholder.
AutoHideEmptyDevices: bool = False
ShowFiletree: bool = True
FiletreeRoot: str = "/"
FiletreeRoot: str = DefaultFiletreeRoot
BookmarksMinHeight: int = 0 # 0 = no constraint
BookmarksMaxHeight: int = 0
DevicesMinHeight: int = 0
@@ -552,9 +566,41 @@ def ApplyAppearance(Settings: SharedSettings) -> None:
ActiveFontFamily = Settings.FontFamily or BundledFontFamily
def _WindowsFonts() -> set[str]:
"""Font families from the system and per-user Fonts registry keys
("Arial Bold (TrueType)" -> "Arial")."""
import re
import winreg
Families: set[str] = set()
Key = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
for Root in (winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER):
try:
with winreg.OpenKey(Root, Key) as Fonts:
Index = 0
while True:
try:
Name = winreg.EnumValue(Fonts, Index)[0]
except OSError:
break
Index += 1
Name = re.sub(r"\s*\(.*\)$", "", Name)
Name = re.sub(r"\s+(Bold|Italic|Light|Semibold|SemiBold|Black|Regular|Medium|Thin)\b.*$", "", Name)
if Name and "&" not in Name:
Families.add(Name.strip())
except OSError:
continue
return Families
def InstalledFontFamilies() -> list[str]:
"""Font families fontconfig knows about, for the font picker. The
bundled font is always first, since it isn't installed system-wide."""
"""Font families fontconfig (or, on Windows, the registry) knows about,
for the font picker. The bundled font is always first, since it isn't
installed system-wide."""
if IsWindows:
Families = _WindowsFonts()
Families.discard(BundledFontFamily)
return [BundledFontFamily] + sorted(Families, key=str.lower)
try:
Result = subprocess.run(["fc-list", ":", "family"], capture_output=True, text=True, timeout=5)
Families = {Line.split(",")[0].strip() for Line in Result.stdout.splitlines() if Line.strip()}