Release the main window's native window when it is closed - #2555
Merged
Conversation
…mory
`objc.loadBundle('Sparkle', ...)` defaults to `scan_classes=True`, which wraps
every Objective-C class in the process (~67,000 on macOS 15) as a Python class
and keeps them in this module's globals for the lifetime of the app. Only the
frozen app bundle takes this path, which is why the shipped Vorta.app idles at
~220-250 MB while a venv install of the same code idles at ~80-120 MB.
Load only the framework and look up `SUUpdater` explicitly instead.
Measured on macOS 15.7 (M3) with a bundle built from this tree, main window
hidden, 35 s after launch: physical footprint 228.8 MB -> 78.6 MB, realized
ObjC classes 66,928 -> 2,322.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Closing the main window only hides it: Qt keeps the native window and its backing store alive for as long as the widget exists, i.e. for the rest of the session once the user has opened the window and put Vorta back into the tray. On a Retina display that is 19-28 MB (depending on the window size) of the ~110 MB the app idles at after the Sparkle fix. Call `QWidget.destroy()` once the close has gone through; `show()` creates the native window again and the window comes back at its previous position and size. Measured (macOS 15.7, PyQt6 6.10, main window closed into the tray): physical footprint 108 MB -> 89 MB, IOSurface 19 MB -> 0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ThomasWaldmann
marked this pull request as draft
September 5, 2026 20:08
9 tasks
ThomasWaldmann
marked this pull request as ready for review
September 5, 2026 20:47
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.
Description
Closing the main window only hides it. Qt keeps the native window and its backing store alive for as long as the widget exists — i.e. for the rest of the session once the user has opened the window and put Vorta back into the tray. On a Retina display that is 19–28 MB (depending on the window size) of the ~110 MB Vorta idles at after #2551.
MainWindow.closeEventnow schedulesQWidget.destroy()for right after the close has gone through (Qt hides the widget only aftercloseEventreturns, hence the zero-timer).show()creates the native window again; the window comes back at its previous position and size, and nothing in Vorta touches the native handle (winId/windowHandleare unused).Tearing the whole
MainWindowdown instead was measured too: it saves only ~3 MB more (the widgets and models) for a 140 ms rebuild plus all theapp.main_windowreferences, so it is not worth it.Related Issue
Follow-up to #2551 (from the investigation for borgbackup/borg#10328).
Motivation and Context
Vorta is a tray-resident app; users open the window, start or check a backup, close it, and then it sits in the tray for days. The closed window's backing store was the largest remaining single item after #2551.
How Has This Been Tested?
New test
tests/unit/test_main_window.py: the native window is gone afterclose()and back after reopening viaopen_main_window_action(). It mocksis_system_tray_availablesocloseEventtakes the tray path on headless CI. Passed on macOS with PyQt6 6.6.1 and 6.10.0, and on Linux/offscreen (Debian, Python 3.12, in a container).Full unit suite on macOS: 266 passed, 7 skipped.
Footprint measured on macOS 15.7 with PyQt6 6.10 (the shipped stack), real event loop, window closed into the tray:
Position/size check: window moved and resized, closed, reopened from the tray → same position and size.
Types of changes
Checklist:
I provide my contribution under the terms of the license of this repository and I affirm the Developer Certificate of Origin.
🤖 Generated with Claude Code