mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
fix(desktop): let macOS system quit bypass background close (#3203)
Let macOS system-level Quit (Dock Quit, app menu Quit, Cmd-Q) bypass the close-to-background preference. Swizzles AppDelegate applicationShouldTerminate: and WailsContext Quit to mark a system-quit flag that beforeClose consumes; ordinary window close behavior unchanged and covered by a regression test.
This commit is contained in:
1 parent
0c020ba4c6
commit
fea1d664f1
6 files changed
+110
-1
No files matched your search
+2
-1
@@ -89,12 +89,13 @@ func (a *App) Platform() string {
|
||||
// off the initialization in a background goroutine so the webview loads immediately.
|
||||
func (a *App) startup(ctx context.Context) {
|
||||
a.ctx = ctx
|
||||
installSystemQuitHook()
|
||||
|
||||
go a.restoreOrBuildTabs()
|
||||
}
|
||||
|
||||
func (a *App) beforeClose(ctx context.Context) bool {
|
||||
if a.forceQuit.Swap(false) {
|
||||
if a.forceQuit.Swap(false) || consumeSystemQuitRequested() {
|
||||
return false
|
||||
}
|
||||
cfg, _, err := a.loadDesktopUserConfigForEdit()
|
||||
|
||||
@@ -73,6 +73,28 @@ func TestEffortDefaultsBeforeStartup(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeforeCloseAllowsSystemQuitWhenBackgroundCloseEnabled(t *testing.T) {
|
||||
isolateDesktopUserDirs(t)
|
||||
consumeSystemQuitRequested()
|
||||
t.Cleanup(func() { consumeSystemQuitRequested() })
|
||||
|
||||
userCfg := config.LoadForEdit(config.UserConfigPath())
|
||||
if err := userCfg.SetDesktopCloseBehavior("background"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := userCfg.SaveTo(config.UserConfigPath()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
markSystemQuitRequested()
|
||||
if prevent := NewApp().beforeClose(context.Background()); prevent {
|
||||
t.Fatal("system quit should bypass background close-to-tray behavior")
|
||||
}
|
||||
if consumeSystemQuitRequested() {
|
||||
t.Fatal("system quit marker should be consumed by beforeClose")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmitReadyInvokesReadyHook(t *testing.T) {
|
||||
app := NewApp()
|
||||
var calls int32
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
var systemQuitRequested atomic.Bool
|
||||
|
||||
func markSystemQuitRequested() {
|
||||
systemQuitRequested.Store(true)
|
||||
}
|
||||
|
||||
func consumeSystemQuitRequested() bool {
|
||||
return systemQuitRequested.Swap(false)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//go:build darwin
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo darwin LDFLAGS: -framework Cocoa
|
||||
void installReasonixSystemQuitHook(void);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "sync"
|
||||
|
||||
var installSystemQuitHookOnce sync.Once
|
||||
|
||||
func installSystemQuitHook() {
|
||||
installSystemQuitHookOnce.Do(func() {
|
||||
C.installReasonixSystemQuitHook()
|
||||
})
|
||||
}
|
||||
|
||||
//export ReasonixMarkSystemQuit
|
||||
func ReasonixMarkSystemQuit() {
|
||||
markSystemQuitRequested()
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//go:build darwin
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
extern void ReasonixMarkSystemQuit(void);
|
||||
|
||||
static NSApplicationTerminateReply (*originalApplicationShouldTerminate)(id, SEL, NSApplication *);
|
||||
static void (*originalWailsContextQuit)(id, SEL);
|
||||
|
||||
static NSApplicationTerminateReply reasonixApplicationShouldTerminate(id self, SEL _cmd, NSApplication *sender) {
|
||||
ReasonixMarkSystemQuit();
|
||||
if (originalApplicationShouldTerminate != NULL) {
|
||||
return originalApplicationShouldTerminate(self, _cmd, sender);
|
||||
}
|
||||
return NSTerminateNow;
|
||||
}
|
||||
|
||||
static void reasonixWailsContextQuit(id self, SEL _cmd) {
|
||||
ReasonixMarkSystemQuit();
|
||||
if (originalWailsContextQuit != NULL) {
|
||||
originalWailsContextQuit(self, _cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void installReasonixSystemQuitHook(void) {
|
||||
Class appDelegate = NSClassFromString(@"AppDelegate");
|
||||
SEL selector = @selector(applicationShouldTerminate:);
|
||||
Method method = appDelegate == Nil ? NULL : class_getInstanceMethod(appDelegate, selector);
|
||||
if (method != NULL) {
|
||||
IMP replacement = (IMP)reasonixApplicationShouldTerminate;
|
||||
IMP previous = method_setImplementation(method, replacement);
|
||||
originalApplicationShouldTerminate = (NSApplicationTerminateReply (*)(id, SEL, NSApplication *))previous;
|
||||
}
|
||||
|
||||
Class wailsContext = NSClassFromString(@"WailsContext");
|
||||
SEL quitSelector = @selector(Quit);
|
||||
Method quitMethod = wailsContext == Nil ? NULL : class_getInstanceMethod(wailsContext, quitSelector);
|
||||
if (quitMethod != NULL) {
|
||||
IMP replacement = (IMP)reasonixWailsContextQuit;
|
||||
IMP previous = method_setImplementation(quitMethod, replacement);
|
||||
originalWailsContextQuit = (void (*)(id, SEL))previous;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
//go:build !darwin
|
||||
|
||||
package main
|
||||
|
||||
func installSystemQuitHook() {}
|
||||
Reference in new issue
Block a user