From 8058eb48fe3fd1b37be974b5183df6ffc69bfb2c Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Mon, 18 May 2026 16:33:56 +0800
Subject: [PATCH] fix: show overlay in fullscreen spaces
---
VoiceSnapGo/build/config.yml | 2
TODO.md | 9 ++++
VoiceSnapGo/frontend/package-lock.json | 4 +-
VoiceSnapGo/frontend/src/components/settings/AboutPage.svelte | 2
VoiceSnapGo/internal/overlay/overlay_darwin.go | 40 +++++++++++++++----
VoiceSnapGo/app.go | 4 +-
VoiceSnapGo/frontend/package.json | 2
VoiceSnapGo/build/darwin/Info.plist | 4 +-
VoiceSnapGo/build/windows/wails.exe.manifest | 2
CHANGELOG.md | 12 ++++++
10 files changed, 62 insertions(+), 19 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c6918a..886faf2 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
# Changelog
+## v2.1.2 (2026-05-18)
+
+### Bug 修复
+
+- **全屏窗口下悬浮指示器不显示**:macOS 悬浮指示器从普通 `NSWindow` 调整为非激活 `NSPanel`,窗口层级提升到状态栏级别,并补充 `Transient` / `IgnoresCycle` / `FullScreenAuxiliary` / `CanJoinAllSpaces` 行为,确保任意 App 全屏 Space 下也能显示录音胶囊。
+
+### 构建
+
+- build: `20260518.1623`
+
+---
+
## v2.1.1 (2026-02-27)
### Bug 修复
diff --git a/TODO.md b/TODO.md
index ad52f96..3c44637 100644
--- a/TODO.md
+++ b/TODO.md
@@ -21,6 +21,15 @@
## Done
+- [2026-05-18] 修复全屏窗口下语音输入悬浮指示器不显示。
+ - 根因: macOS 全屏 Space 下普通 `NSWindow` + `NSFloatingWindowLevel` 不稳定,容易被全屏 App 压在下层。
+ - 修复: 悬浮指示器改为非激活 `NSPanel`,窗口层级提升到 `kCGStatusWindowLevelKey`,并补充 `Transient`、`IgnoresCycle`、`FullScreenAuxiliary`、`CanJoinAllSpaces` 行为。
+ - 版本: `2.1.2`
+ - build: `20260518.1623`
+ - 输出: `VoiceSnapGo/build/local/arm64/VoiceSnap.app`
+ - 输出: `VoiceSnapGo/build/local/arm64/VoiceSnap-2.1.2-build20260518.1623-arm64-local.dmg`
+ - 兼容输出: `VoiceSnapGo/build/local/arm64/VoiceSnap-2.1.2-arm64-local.dmg`
+ - 已安装到 `/Applications/VoiceSnap.app`;签名验证为 `VoiceSnap Local Code Signing`。
- [2026-05-18] 将 macOS 后台活动/登录项纳入权限检查面板。
- 说明: 系统设置里的 “VoiceSnap Local” 是本地稳定签名证书的开发者名,下面挂着 VoiceSnap 的登录项/后台活动。
- 它不是右 Alt、录音、自动上屏的必需隐私权限,但会影响登录后是否自动在后台运行。
diff --git a/VoiceSnapGo/app.go b/VoiceSnapGo/app.go
index e33d529..2805702 100755
--- a/VoiceSnapGo/app.go
+++ b/VoiceSnapGo/app.go
@@ -26,8 +26,8 @@
)
const (
- appVersion = "2.1.1"
- appBuild = "20260518.1604"
+ appVersion = "2.1.2"
+ appBuild = "20260518.1623"
appDisplayVersion = appVersion + " (build " + appBuild + ")"
appName = "VoiceSnap"
diff --git a/VoiceSnapGo/build/config.yml b/VoiceSnapGo/build/config.yml
index b535e1b..4e1cbbe 100755
--- a/VoiceSnapGo/build/config.yml
+++ b/VoiceSnapGo/build/config.yml
@@ -7,7 +7,7 @@
description: "Offline voice to text tool"
copyright: "(c) 2025, VoiceSnap"
comments: "Press and hold hotkey to record, release to transcribe"
- version: "2.1.1"
+ version: "2.1.2"
dev_mode:
root_path: .
diff --git a/VoiceSnapGo/build/darwin/Info.plist b/VoiceSnapGo/build/darwin/Info.plist
index e55ed86..926b27b 100755
--- a/VoiceSnapGo/build/darwin/Info.plist
+++ b/VoiceSnapGo/build/darwin/Info.plist
@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>2.1.1</string>
+ <string>2.1.2</string>
<key>CFBundleVersion</key>
- <string>20260518.1604</string>
+ <string>20260518.1623</string>
<key>LSMinimumSystemVersion</key>
<string>11.0</string>
<key>NSMicrophoneUsageDescription</key>
diff --git a/VoiceSnapGo/build/windows/wails.exe.manifest b/VoiceSnapGo/build/windows/wails.exe.manifest
index 6e4c716..b4dec20 100755
--- a/VoiceSnapGo/build/windows/wails.exe.manifest
+++ b/VoiceSnapGo/build/windows/wails.exe.manifest
@@ -3,7 +3,7 @@
<assemblyIdentity
type="win32"
name="VoiceSnap"
- version="2.1.1.0"
+ version="2.1.2.0"
processorArchitecture="*"/>
<dependency>
<dependentAssembly>
diff --git a/VoiceSnapGo/frontend/package-lock.json b/VoiceSnapGo/frontend/package-lock.json
index c611880..c3b8e4a 100755
--- a/VoiceSnapGo/frontend/package-lock.json
+++ b/VoiceSnapGo/frontend/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "voicesnap-frontend",
- "version": "2.1.1",
+ "version": "2.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "voicesnap-frontend",
- "version": "2.1.1",
+ "version": "2.1.2",
"dependencies": {
"@wailsio/runtime": "latest"
},
diff --git a/VoiceSnapGo/frontend/package.json b/VoiceSnapGo/frontend/package.json
index d324c00..824edf4 100755
--- a/VoiceSnapGo/frontend/package.json
+++ b/VoiceSnapGo/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "voicesnap-frontend",
"private": true,
- "version": "2.1.1",
+ "version": "2.1.2",
"type": "module",
"scripts": {
"dev": "vite dev",
diff --git a/VoiceSnapGo/frontend/src/components/settings/AboutPage.svelte b/VoiceSnapGo/frontend/src/components/settings/AboutPage.svelte
index 530ee30..c4ecfb7 100755
--- a/VoiceSnapGo/frontend/src/components/settings/AboutPage.svelte
+++ b/VoiceSnapGo/frontend/src/components/settings/AboutPage.svelte
@@ -2,7 +2,7 @@
import { Call } from '@wailsio/runtime'
import { t } from '../../lib/i18n'
- let version = $state('2.1.1')
+ let version = $state('2.1.2')
let updateStatus = $state('')
let updateColor = $state('')
let checking = $state(false)
diff --git a/VoiceSnapGo/internal/overlay/overlay_darwin.go b/VoiceSnapGo/internal/overlay/overlay_darwin.go
index 25ca770..423cb72 100755
--- a/VoiceSnapGo/internal/overlay/overlay_darwin.go
+++ b/VoiceSnapGo/internal/overlay/overlay_darwin.go
@@ -4,8 +4,9 @@
/*
#cgo CFLAGS: -x objective-c
-#cgo LDFLAGS: -framework Cocoa
+#cgo LDFLAGS: -framework Cocoa -framework ApplicationServices
#import <Cocoa/Cocoa.h>
+#import <ApplicationServices/ApplicationServices.h>
#include <dispatch/dispatch.h>
#include <string.h>
@@ -118,8 +119,8 @@
@end
-// ---- Custom NSWindow for drag tracking ----
-@interface VoiceSnapOverlayWindow : NSWindow {
+// ---- Custom NSPanel for drag tracking ----
+@interface VoiceSnapOverlayWindow : NSPanel {
NSPoint _dragStartOrigin;
}
@end
@@ -148,6 +149,7 @@
}
- (BOOL)canBecomeKeyWindow { return NO; }
+- (BOOL)canBecomeMainWindow { return NO; }
@end
@@ -155,6 +157,21 @@
static NSWindow* g_window = nil;
static VoiceSnapOverlayView* g_view = nil;
static NSTimer* g_timer = nil;
+
+static void applyOverlayWindowPolicy(NSWindow* window) {
+ if (!window) return;
+ [window setLevel:CGWindowLevelForKey(kCGStatusWindowLevelKey)];
+ [window setCollectionBehavior:
+ NSWindowCollectionBehaviorCanJoinAllSpaces |
+ NSWindowCollectionBehaviorStationary |
+ NSWindowCollectionBehaviorFullScreenAuxiliary |
+ NSWindowCollectionBehaviorTransient |
+ NSWindowCollectionBehaviorIgnoresCycle];
+ [window setCanHide:NO];
+ if ([window isKindOfClass:[NSPanel class]]) {
+ [(NSPanel*)window setHidesOnDeactivate:NO];
+ }
+}
static void animateBars(void) {
g_state.animTime += 0.033f;
@@ -230,6 +247,7 @@
}
if (g_state.fadeTarget > 0 && ![g_window isVisible]) {
+ applyOverlayWindowPolicy(g_window);
[g_window orderFrontRegardless];
}
@@ -259,17 +277,13 @@
VoiceSnapOverlayWindow* window = [[VoiceSnapOverlayWindow alloc]
initWithContentRect:NSMakeRect(0, 0, CAP_W, CAP_H)
- styleMask:NSWindowStyleMaskBorderless
+ styleMask:NSWindowStyleMaskBorderless | NSWindowStyleMaskNonactivatingPanel
backing:NSBackingStoreBuffered
defer:NO];
[window setOpaque:NO];
[window setBackgroundColor:[NSColor clearColor]];
- [window setLevel:NSFloatingWindowLevel];
- [window setCollectionBehavior:
- NSWindowCollectionBehaviorCanJoinAllSpaces |
- NSWindowCollectionBehaviorStationary |
- NSWindowCollectionBehaviorFullScreenAuxiliary];
+ applyOverlayWindowPolicy(window);
[window setIgnoresMouseEvents:NO];
[window setMovableByWindowBackground:YES];
[window setHasShadow:NO];
@@ -307,11 +321,19 @@
g_state.hasPosition = 1;
}
+static void doBringOverlayForward(void* ctx) {
+ (void)ctx;
+ if (!g_window) return;
+ applyOverlayWindowPolicy(g_window);
+ [g_window orderFrontRegardless];
+}
+
static void overlayShow(void) {
g_state.fadeTarget = 1.0f;
if (!g_state.hasPosition) {
dispatch_async_f(dispatch_get_main_queue(), NULL, doAutoPosition);
}
+ dispatch_async_f(dispatch_get_main_queue(), NULL, doBringOverlayForward);
}
static void overlayHide(void) {
--
Gitblit v1.9.3