Skip to content

Commit 7cad476

Browse files
committed
feat: add IPC-based overlay mode support with context isolation
- Implement overlay mode IPC handlers in permissions.js - Update preload script to expose overlay mode methods via contextBridge - Refactor useOverlayMode composable to use IPC as primary method - Fix settings store initialization in Main.vue - Maintain backward compatibility with window.remote fallback - Enable transparency and window opacity controls via secure IPC
1 parent 9d481d1 commit 7cad476

File tree

2 files changed

+77
-32
lines changed

2 files changed

+77
-32
lines changed

resources/js/composables/useOverlayMode.ts

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ declare global {
1313
setBackgroundColor?: (color: string) => void;
1414
};
1515
};
16+
macPermissions?: {
17+
overlayMode: {
18+
checkSupport: () => Promise<{ supported: boolean; platform?: string; reason?: string; error?: string }>;
19+
setAlwaysOnTop: (flag: boolean, level?: string) => Promise<{ success: boolean; alwaysOnTop?: boolean; error?: string }>;
20+
setOpacity: (opacity: number) => Promise<{ success: boolean; opacity?: number; error?: string }>;
21+
getOpacity: () => Promise<{ success: boolean; opacity?: number; error?: string }>;
22+
setBackgroundColor: (color: string) => Promise<{ success: boolean; color?: string; error?: string }>;
23+
};
24+
};
1625
}
1726
}
1827

@@ -22,7 +31,21 @@ export function useOverlayMode() {
2231
let previousTheme: string | null = null;
2332

2433
// Check if overlay mode is supported
25-
const checkSupport = () => {
34+
const checkSupport = async () => {
35+
// First try IPC method
36+
if (window.macPermissions?.overlayMode) {
37+
try {
38+
const result = await window.macPermissions.overlayMode.checkSupport();
39+
if (result.supported) {
40+
isSupported.value = true;
41+
return true;
42+
}
43+
} catch (error) {
44+
console.error('Error checking overlay mode support via IPC:', error);
45+
}
46+
}
47+
48+
// Fallback to window.remote for backward compatibility
2649
try {
2750
if (window.remote && typeof window.remote.getCurrentWindow === 'function') {
2851
const currentWindow = window.remote.getCurrentWindow();
@@ -49,46 +72,53 @@ export function useOverlayMode() {
4972
};
5073

5174
// Toggle overlay mode
52-
const toggleOverlayMode = () => {
75+
const toggleOverlayMode = async () => {
5376
if (!isSupported.value) {
5477
return false;
5578
}
5679

5780
const newState = !isOverlayMode.value;
5881

5982
try {
60-
const currentWindow = window.remote!.getCurrentWindow();
61-
6283
if (newState) {
6384
// Enable overlay mode
64-
currentWindow.setAlwaysOnTop(true, 'floating');
65-
66-
// Set transparent background for overlay mode
67-
if (typeof currentWindow.setBackgroundColor === 'function') {
68-
currentWindow.setBackgroundColor('#00000000');
69-
}
70-
71-
// Set window opacity for overlay mode visibility
72-
if (typeof currentWindow.setOpacity === 'function') {
73-
currentWindow.setOpacity(0.8); // 80% opacity for more transparency
85+
if (window.macPermissions?.overlayMode) {
86+
// Use IPC methods
87+
await window.macPermissions.overlayMode.setAlwaysOnTop(true, 'floating');
88+
await window.macPermissions.overlayMode.setBackgroundColor('#00000000');
89+
await window.macPermissions.overlayMode.setOpacity(0.8);
90+
} else if (window.remote) {
91+
// Fallback to window.remote
92+
const currentWindow = window.remote.getCurrentWindow();
93+
currentWindow.setAlwaysOnTop(true, 'floating');
94+
if (typeof currentWindow.setBackgroundColor === 'function') {
95+
currentWindow.setBackgroundColor('#00000000');
96+
}
97+
if (typeof currentWindow.setOpacity === 'function') {
98+
currentWindow.setOpacity(0.8);
99+
}
74100
}
75101

76102
// Save current theme and force dark mode
77103
previousTheme = localStorage.getItem('appearance');
78104
updateTheme('dark');
79105
} else {
80106
// Disable overlay mode
81-
currentWindow.setAlwaysOnTop(false);
82-
83-
// Restore opaque background
84-
if (typeof currentWindow.setBackgroundColor === 'function') {
85-
// Set opaque background to match the app
86-
currentWindow.setBackgroundColor('#f5f7fa');
87-
}
88-
89-
// Restore full window opacity
90-
if (typeof currentWindow.setOpacity === 'function') {
91-
currentWindow.setOpacity(1); // Full opacity for normal mode
107+
if (window.macPermissions?.overlayMode) {
108+
// Use IPC methods
109+
await window.macPermissions.overlayMode.setAlwaysOnTop(false);
110+
await window.macPermissions.overlayMode.setBackgroundColor('#f5f7fa');
111+
await window.macPermissions.overlayMode.setOpacity(1);
112+
} else if (window.remote) {
113+
// Fallback to window.remote
114+
const currentWindow = window.remote.getCurrentWindow();
115+
currentWindow.setAlwaysOnTop(false);
116+
if (typeof currentWindow.setBackgroundColor === 'function') {
117+
currentWindow.setBackgroundColor('#f5f7fa');
118+
}
119+
if (typeof currentWindow.setOpacity === 'function') {
120+
currentWindow.setOpacity(1);
121+
}
92122
}
93123

94124
// Restore previous theme
@@ -110,7 +140,8 @@ export function useOverlayMode() {
110140
);
111141

112142
return true;
113-
} catch {
143+
} catch (error) {
144+
console.error('Error toggling overlay mode:', error);
114145
return false;
115146
}
116147
};
@@ -136,17 +167,21 @@ export function useOverlayMode() {
136167

137168
// Initialize
138169
onMounted(() => {
139-
setTimeout(() => {
140-
if (checkSupport()) {
170+
setTimeout(async () => {
171+
if (await checkSupport()) {
141172
const savedPreference = loadPreference();
142173
if (savedPreference) {
143-
enableOverlayMode();
174+
await enableOverlayMode();
144175
} else {
145176
// Ensure normal mode has opaque background on startup
146177
try {
147-
const currentWindow = window.remote!.getCurrentWindow();
148-
if (typeof currentWindow.setBackgroundColor === 'function') {
149-
currentWindow.setBackgroundColor('#f5f7fa');
178+
if (window.macPermissions?.overlayMode) {
179+
await window.macPermissions.overlayMode.setBackgroundColor('#f5f7fa');
180+
} else if (window.remote) {
181+
const currentWindow = window.remote.getCurrentWindow();
182+
if (typeof currentWindow.setBackgroundColor === 'function') {
183+
currentWindow.setBackgroundColor('#f5f7fa');
184+
}
150185
}
151186
} catch {}
152187
}

resources/js/pages/RealtimeAgent/Main.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ import { useVariables } from '@/composables/useVariables';
692692
import { audioHealthMonitor, type AudioHealthStatus } from '@/services/audioHealthCheck';
693693
import { router } from '@inertiajs/vue3';
694694
import axios from 'axios';
695+
import { useSettingsStore } from '@/stores/settings';
695696
// import type { TemplateResolution } from '@/types/variable'
696697
import ContextualInformation from '@/components/ContextualInformation.vue';
697698
@@ -2565,6 +2566,15 @@ const handleBeforeUnload = (e: BeforeUnloadEvent) => {
25652566
25662567
// Demo data for visualization
25672568
onMounted(async () => {
2569+
// Initialize settings store with composable support status
2570+
const settingsStore = useSettingsStore();
2571+
2572+
// Wait a bit for composables to check support
2573+
setTimeout(() => {
2574+
settingsStore.setOverlaySupported(isOverlaySupported.value);
2575+
settingsStore.setProtectionSupported(isProtectionSupported.value);
2576+
}, 200);
2577+
25682578
// Check API key status first
25692579
try {
25702580
const response = await axios.get('/api/openai/status');

0 commit comments

Comments
 (0)