Windows support in SaraSuite

This commit is contained in:
sarah committed 2026-10-09 13:59:08 +02:00
1 parent 3998dfde74
commit 92033f3bf6
9 files changed
+627 -75

No files matched your search

+42 -11
View File
@@ -6,6 +6,7 @@ import os
import shutil
import sys
import traceback
from pathlib import Path
from typing import Callable
import flet as ft
@@ -13,7 +14,7 @@ import flet as ft
import SelfUpdate
from Catalog import UpdateCatalog
from Core import (
AppName, AppVersion, ApplyAppearance, AssetsDir, BuildTheme, BundledFontFamily, ChipButtonStyle, DataDir,
AppName, AppVersion, IsWindows, StartMenuDir, ApplyAppearance, AssetsDir, BuildTheme, BundledFontFamily, ChipButtonStyle, DataDir,
BundledManifestsDir, DataHome, EffectiveSettings, LoadConfig, Palette,
)
from Dialogs import ShowInstallDialog, ShowOptionsDialog, ShowRemoveDialog, ShowUpdateDialog
@@ -24,10 +25,17 @@ from Settings import ShowSettingsDialog
_MaxLogLines = 2000
# When running as an AppImage, SaraSuite can put itself in the app menu.
_AppImage = os.environ.get("APPIMAGE", "")
_MenuEntry = DataHome / "applications" / "SaraSuite.desktop"
_MenuIcon = DataDir / "SaraSuite.png"
# When running packaged (AppImage / .exe), SaraSuite can put itself in the
# app menu: a desktop entry on Linux, a Start Menu shortcut on Windows.
_Packaged = SelfUpdate.RunningAppImage()
_AppImage = str(_Packaged) if _Packaged else ""
if IsWindows:
_MenuEntry = StartMenuDir / "SaraSuite.lnk"
_MenuIcon = DataDir / "SaraSuite.ico"
else:
_MenuEntry = DataHome / "applications" / "SaraSuite.desktop"
_MenuIcon = DataDir / "SaraSuite.png"
_MenuLabel = "Start menu" if IsWindows else "app menu"
def _LoadFletIdentity():
@@ -44,6 +52,12 @@ def _SetMenuEntry(Enabled: bool) -> None:
_MenuEntry.unlink(missing_ok=True)
_MenuIcon.unlink(missing_ok=True)
return
if IsWindows:
import WindowsSupport
Icon = WindowsSupport.MakeIcon(AssetsDir / "Icon.png", _MenuIcon)
WindowsSupport.CreateShortcut(_MenuEntry, Path(_AppImage), Icon=Icon, Description="Install, update and remove Sara programs")
return
_MenuIcon.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(AssetsDir / "Icon.png", _MenuIcon)
_MenuEntry.parent.mkdir(parents=True, exist_ok=True)
@@ -70,6 +84,13 @@ def Main(Page: ft.Page) -> None:
Page.bgcolor = Palette.Base
Page.window.width = 960
Page.window.height = 720
if IsWindows:
# The taskbar/title bar icon (on Linux it comes from the desktop entry).
import WindowsSupport
Icon = WindowsSupport.MakeIcon(AssetsDir / "Icon.png", DataDir / "SaraSuite.ico")
if Icon is not None:
Page.window.icon = str(Icon)
LogView = ft.ListView(expand=True, auto_scroll=True, spacing=0, padding=8)
@@ -242,11 +263,11 @@ def Main(Page: ft.Page) -> None:
def ToggleMenuEntry(e) -> None:
_SetMenuEntry(not _MenuEntry.exists())
MenuButton.content = "Remove from app menu" if _MenuEntry.exists() else "Add to app menu"
MenuButton.content = f"Remove from {_MenuLabel}" if _MenuEntry.exists() else f"Add to {_MenuLabel}"
MenuButton.update()
MenuButton = ft.OutlinedButton(
content="Remove from app menu" if _MenuEntry.exists() else "Add to app menu",
content=f"Remove from {_MenuLabel}" if _MenuEntry.exists() else f"Add to {_MenuLabel}",
style=ChipButtonStyle(),
visible=bool(_AppImage),
on_click=ToggleMenuEntry,
@@ -304,11 +325,21 @@ def Main(Page: ft.Page) -> None:
if __name__ == "__main__":
if len(sys.argv) > 1:
if IsWindows and getattr(sys, "frozen", False):
# The .exe is built windowed (no console of its own); write the
# command-line mode's output to the console it was started from.
import ctypes
if ctypes.windll.kernel32.AttachConsole(-1):
sys.stdout = open("CONOUT$", "w", encoding="utf-8", buffering=1)
sys.stderr = sys.stdout
from Cli import Run
sys.exit(Run(sys.argv[1:]))
# A Flet client copy with the window app ID srhtnin.SaraSuite, so the
# desktop matches the window to SaraSuite.desktop (StartupWMClass) instead
# of showing it as "com.appveyor.flet". See Programs/FletIdentity.py.
os.environ.setdefault("FLET_VIEW_PATH", _LoadFletIdentity().ClientFor(f"srhtnin.{AppName}"))
SelfUpdate.CleanUpOldExe()
if not IsWindows:
# A Flet client copy with the window app ID srhtnin.SaraSuite, so the
# desktop matches the window to SaraSuite.desktop (StartupWMClass) instead
# of showing it as "com.appveyor.flet". See Programs/FletIdentity.py.
os.environ.setdefault("FLET_VIEW_PATH", _LoadFletIdentity().ClientFor(f"srhtnin.{AppName}"))
ft.run(Main, assets_dir=str(AssetsDir))