Repository navigation
Brandy: one-click Steam on Wine 11, modern UI, rebrand and audit fixes - #4
Merged
Merged
Conversation
Clearer information with stock SwiftUI and AppKit controls, so the app
follows the system look, accent color and dark mode.
- Sidebar: each bottle shows its Windows version, or that its files are
missing. Standard empty states for no bottles and no selection.
- Bottle page: a header with Windows version, Wine version and program
count; pinned programs as tiles that show Run on hover; Programs and
Configuration rows that preview their contents. Run and the bottle
actions move from a bottom bar to the window toolbar.
- Configuration: every setting has a one-line explanation, DPI shows its
value, sections no longer collapse, and Control Panel, Registry Editor
and Wine Configuration get their own section.
- Programs: icons, names without .exe, the Windows folder each program
is in, and Pinned and Hidden groups ("Blocklist" is now "Hidden").
- Program page: header with icon and location, Run and More in the
toolbar, labelled Launch and Environment Variables sections.
- Icons are extracted once, off the main thread, and shared between
screens.
- Remove BottomBar, which nothing uses anymore.
Fixes
- Opening Configuration wrote DPI 0 to the registry of any bottle whose
DPI was never changed. DPI is now written only when changed in its
sheet, and a stored 0 shows as the default 96.
- Deleting a bottle left a stub folder behind: loading a program wrote
default settings, and saving recreated the bottle's folder. Loading no
longer writes, and saving skips bottles whose folder is gone.
- Opening a bottle stopped pinning Start Menu programs after the first
one that was already pinned.
scripts/build-whiskywine.sh assembles the Libraries folder from: - Wine 11.0 stable, the official WineHQ macOS package (Gcenx/macOS_Wine_builds 11.0_1), which already includes Mono, Gecko and MoltenVK - DXVK-macOS 1.10.3, using the plain variant: Wine ignores DLLs marked as builtin when they are copied into system32, which is how Whisky enables DXVK - winetricks and its verb list at a pinned commit Each download is checked against a pinned SHA-256. The publish script now uploads to a release per runtime major version (whiskywine-3), so a build only downloads a runtime whose layout it supports, and checks for Wine 11's `wine` launcher instead of `wine64`.
First run is now a single flow: Set Up Steam installs Rosetta, downloads the Wine 11 runtime, creates a bottle, downloads Steam from Valve, installs it silently and offers Open Steam. Each step reports progress, failures are explained in plain language with Try Again resuming from the failed step, and every step is skipped when already done, so the same flow repairs Steam. After setup the window is a simple home screen with one Open Steam button and Repair Steam. Bottles, programs and Wine settings move behind "Show advanced options" in Settings; choosing "Set up without Steam" turns it on. Wine 11 - Run the `wine` launcher; Wine 9+ has no `wine64`. The Terminal shortcut no longer needs aliases because Wine 11 ships winecfg, regedit and friends. - Download runtime 3 from the whiskywine-3 release, and treat an older runtime as missing so setup replaces it. - Find Start Menu shortcuts in the profile Wine names after the macOS user, as well as CrossOver's `crossover` profile. - Remove Enhanced Sync: MSync and ESync are CrossOver patches with no effect on Wine 11. Windows versions - Offer only Windows 10 and 11. Bottles stored as XP to 8.1 load as Windows 10 instead of failing to decode, which would have reset their name and pins, and their Wine prefix is switched to Windows 10 once. Shared pieces - WhiskyKit Download: validated downloads with progress and cancellation, used for both the runtime and the Steam installer. - WhiskyKit SteamInstaller: Valve's official installer, silent install, and finding the bottle Steam is in. - BottleVM.createBottle awaits creation; Program.launch awaits the program exiting, so the home screen knows when Steam is running. - Remove the six setup screens the onboarding flow replaces, and their strings.
Brandy is distilled from wine, as this app is distilled from Whisky: Wine -> Whisky -> Brandy. Everything users see changes; internal code module names (WhiskyKit, WhiskyCmd, the Whisky target) stay to keep the diff focused. - App: Brandy.app with a new icon, a brandy snifter of amber on mahogany drawn for every macOS size; bundle IDs com.istorry.Brandy, com.istorry.Brandy.Thumbnail and com.istorry.BrandyCmd. The Swift module keeps its name through PRODUCT_MODULE_NAME. - Text: every string in every language says Brandy, and the runtime is BrandyWine. The upstream-import messages keep "Whisky" because they name the original app. - Menus: Help links to this repository instead of upstream's website and Discord. The move-to-Applications check looks for Brandy.app. - CLI: the command is `brandy`, installed as /usr/local/bin/brandy. - Logs and paths: log headers read "Brandy Version", and container paths display as ~/Library/Containers/Brandy. - Updates: the Sparkle feed points at this repository's releases instead of upstream's appcast, and upstream's signing key is removed. An own signing key is needed before the first update is published. - README describes Brandy on Wine 11 and credits Whisky and the projects it builds on. Upstream's CodeWeavers affiliate block and its logos are removed. - Issue templates ask for the Brandy version and drop the malformed link to upstream's Discord.
Black window Steam's interface is Chromium (steamwebhelper.exe). On Wine 11 for macOS it composites in a separate GPU process and presents through DirectComposition, neither of which Wine's Mac driver supports, so every window stays black. Steam forwards none of the Chromium switches that fix this; -cef-disable-gpu, -cef-single-process and -cef-in-process-gpu were all tried, as was running Steam's processes on DXVK. - scripts/steamwebhelper-shim.c: a small Windows program that stands in for steamwebhelper.exe and starts Steam's helper with --no-sandbox --disable-gpu --disable-gpu-compositing --in-process-gpu --disable-direct-composition, following Carafe's approach on the same Wine builds. - The runtime build compiles it with mingw-w64; runtime 3.1.0 includes it, and the app now requires 3.1 so setup replaces 3.0. - SteamInstaller installs the shim, keeping Steam's helper as steamwebhelper_real.exe, and reinstalls it before each launch because Steam updates restore their own helper. Steam starts with -noverifyfiles so its file check does not undo it. Program.launch applies this to every way of opening Steam. - Setup gains an "Updating Steam" step that runs Steam's first self-update with progress, stops it, and installs the shim, so the first Open Steam already draws and nobody waits on a silent button. Duplicate launches Clicking Open Steam again while Steam was still updating started a second Steam that raced the first. "Steam is running" followed the launched process, which exits as soon as it hands off to a running Steam. - WineProcesses finds a bottle's Windows programs from the arguments and environment macOS records for each process (WINEPREFIX and the Windows program name), skipping the padding Wine leaves after rewriting arguments. - SteamSession opens Steam at most once per bottle; when Steam is running the button reads Show Steam and brings its windows forward instead. Quitting - "Terminate Wine processes when Brandy closes" never ran: the stop was started on a detached task during termination, and the setting read as off until changed because its default was only declared in SettingsView. Quit now stops bottles synchronously and the default is registered at launch. - Wine.killBottle threw nothing and dropped the stop's errors; it is replaced by an awaitable Wine.stopAllProcesses whose failures are logged.
CLI (Whisky-App#965, Whisky-App#1088, Whisky-App#1140, Whisky-App#1325) - `run` started the program on a detached task and exited before it ran, and ignored the program's arguments. It now waits for the program and passes its arguments through. - `create` made a folder and metadata but no Wine prefix (the setup was commented out). It now uses the same creation code as the app, with --windows win10|win11. - `add` decoded the bottle folder as if it were Metadata.plist, so it always failed; it also allowed duplicates. - `delete` removed the bottle from the list before deleting it, then only printed a failure and exited successfully. - Remove the empty export/install/uninstall commands. Shared bottle creation - Bottle.create in WhiskyKit validates, creates the folder, sets up the prefix and removes everything if that fails; the app and CLI both use it. Errors people never saw - Moving, exporting or removing a bottle, running a program from the Run button or from Finder, creating a shortcut, opening a Wine tool and moving the app to Applications printed failures to the console. They now show an alert (ErrorAlert). Configuration rows already showed failures, so their errors are logged instead of printed. - Winetricks showed an empty sheet when its verb list was missing; it now says it couldn't load. - Moving a bottle rewrote its pins to the new path before moving it, so a failed move left them pointing nowhere; moving and removing also left the bottle stuck as in progress on failure. Correctness - FileManager.replaceDLLs returned at the first file that was not a DLL instead of skipping it, so DXVK could be half installed. - Shortcut apps made their launch script world-writable (0777); it is 0755. - Executables without an icon got an empty image instead of the placeholder. - Non-Unicode Start Menu shortcuts were decoded as Turkish (CP1254) instead of Western (CP1252). - One "run file" helper replaces two copies of the batch-or-program logic. Performance - Opening a bottle walked all of Program Files, including Steam's game library, on the main thread. The walk now runs in the background, and the hidden list is a set instead of being searched for every file. Dead code - Remove the unreachable Running Processes view (it also waited 2,000 nanoseconds where it meant two seconds), WhiskyWineInstaller.uninstall and their strings.
Shift-click "run in Terminal" failed with "Expected end of line, etc. but found identifier" (Whisky-App#712, Whisky-App#942, Whisky-App#1139): the shell command put each environment value in double quotes, and only backslashes were escaped before embedding it in an AppleScript string, so the first quote ended it. The same values were also open to shell expansion of $, backticks and quotes in paths, and Open in Terminal put the bottle's name inside double quotes, so a name containing $(...) would run as a command. - String.shellQuoted (POSIX single quotes) and String.appleScriptQuoted replace String.esc and the three hand-escaped AppleScript blocks. - Terminal.run opens Terminal with a command and throws when AppleScript fails; Shift-click, Open in Terminal and Winetricks use it. - Terminal commands and shortcut apps get Steam's launch preparation too, so a Steam shortcut or Shift-click launch also draws its window. - Tests round-trip quoting through /bin/sh and AppleScript, and compile the Terminal script for paths with quotes, spaces, parentheses, $ and backslashes. - Replace the idle-CPU test, which measured the whole test process and failed when other tests ran in parallel, with a direct check that the pipes' readability handlers are removed at end of file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Turns the fork into Brandy: someone with no technical knowledge opens the app, clicks Set Up Steam, and ends up in Steam's sign-in window. Seven commits, each self-contained.
What changed
One-click Steam on Wine 11
scripts/build-whiskywine.shassembles it from pinned, checksum-verified releases. BrandyWine 3.1.0 is already published as thewhiskywine-3release.Steam's black window and duplicate launches
steamwebhelper.exeshim (scripts/steamwebhelper-shim.c, built into the runtime) starts it with--disable-gpu --in-process-gpu --disable-direct-compositionand two more switches, following Carafe's approach on the same Wine builds. Brandy reinstalls the shim when Steam updates replace it.steam.exeper bottle and shows its windows instead.Modern UI
Rebrand to Brandy
com.istorry.Brandy), strings in every language, CLI (brandy), README and issue templates.Audit fixes
runexited before the program started and dropped its arguments.createbuilt no Wine prefix.addalways failed.deletereported success on failure.Testing
--strictis clean, and Whisky and WhiskyCmd build in Release with no warnings.Not covered