Skip to content

Commit c3403a1

Browse files
committed
fix(windows): windows fails to handle events when the dock bar is opened after being closed
1 parent 5784460 commit c3403a1

File tree

7 files changed

+89
-75
lines changed

7 files changed

+89
-75
lines changed

src/main/agent/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ export class ComputerUseAgent {
198198
if (!isValidImage) {
199199
loopCnt -= 1;
200200
snapshotErrCnt += 1;
201+
await sleep(1000);
201202
continue;
202203
}
203204

src/main/main.ts

+34-12
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,13 @@ class AppUpdater {
5959
repo: 'bytedance/UI-TARS-desktop',
6060
host: 'https://update.electronjs.org',
6161
},
62-
updateInterval: '15 minutes',
62+
updateInterval: '20 minutes',
6363
logger,
6464
});
6565
}
6666
}
6767
}
6868

69-
ipcMain.on('ipc-example', async (event, arg) => {
70-
const msgTemplate = (pingPong: string) => `IPC test: ${pingPong}`;
71-
console.log(msgTemplate(arg));
72-
event.reply('ipc-example', msgTemplate('pong'));
73-
});
74-
7569
if (isProd) {
7670
import('source-map-support').then(({ default: sourceMapSupport }) => {
7771
sourceMapSupport.install();
@@ -109,9 +103,9 @@ const initializeApp = async () => {
109103
logger.info('ensureScreenCapturePermission', ensureScreenCapturePermission);
110104
}
111105

112-
// if (isDev) {
113-
await loadDevDebugTools();
114-
// }
106+
if (env.isDev) {
107+
await loadDevDebugTools();
108+
}
115109

116110
logger.info('createTray');
117111
// Tray
@@ -127,7 +121,7 @@ const initializeApp = async () => {
127121
});
128122

129123
logger.info('createMainWindow');
130-
const mainWindow = createMainWindow();
124+
let mainWindow = createMainWindow();
131125
const settingsWindow = createSettingsWindow({ showInBackground: true });
132126

133127
// Remove this if your app does not use auto updates
@@ -156,7 +150,35 @@ const initializeApp = async () => {
156150
...(launcherWindowIns.getWindow() ? [launcherWindowIns.getWindow()!] : []),
157151
]);
158152

159-
app.on('quit', unsubscribe);
153+
app.on('window-all-closed', () => {
154+
logger.info('window-all-closed');
155+
if (!env.isMacOS) {
156+
app.quit();
157+
}
158+
});
159+
160+
app.on('before-quit', () => {
161+
logger.info('before-quit');
162+
const windows = BrowserWindow.getAllWindows();
163+
windows.forEach((window) => window.destroy());
164+
});
165+
166+
app.on('quit', () => {
167+
logger.info('app quit');
168+
unsubscribe();
169+
});
170+
171+
app.on('activate', () => {
172+
logger.info('app activate');
173+
if (!mainWindow || mainWindow.isDestroyed()) {
174+
mainWindow = createMainWindow();
175+
} else {
176+
if (!mainWindow.isVisible()) {
177+
mainWindow.show();
178+
}
179+
mainWindow.focus();
180+
}
181+
});
160182

161183
logger.info('initializeApp end');
162184

src/main/window/index.ts

+19-41
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
* Copyright (c) 2025 Bytedance, Inc. and its affiliates.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
5-
import { BrowserWindow, app, ipcMain, screen } from 'electron';
5+
import { BrowserWindow, screen } from 'electron';
66

77
import { logger } from '@main/logger';
8+
import * as env from '@main/env';
89

910
import { createWindow } from './createWindow';
1011

@@ -25,53 +26,23 @@ export function show() {
2526
}
2627

2728
export function createMainWindow() {
28-
ipcMain.removeHandler('minimize-window');
29-
ipcMain.removeHandler('maximize-window');
30-
ipcMain.removeHandler('close-window');
31-
3229
mainWindow = createWindow({
3330
routerPath: '/',
3431
width: 430,
3532
height: 580,
3633
alwaysOnTop: false,
3734
});
3835

39-
ipcMain.handle('minimize-window', () => {
40-
mainWindow?.minimize();
41-
});
42-
43-
ipcMain.handle('maximize-window', () => {
44-
if (mainWindow?.isMaximized()) {
45-
mainWindow?.unmaximize();
46-
} else {
47-
mainWindow?.maximize();
48-
}
49-
});
50-
51-
ipcMain.handle('close-window', async () => {
52-
if (mainWindow) {
53-
mainWindow.close();
54-
}
55-
});
56-
57-
app.on('activate', () => {
58-
const windows = BrowserWindow.getAllWindows();
59-
const existingWindow = windows.find((win) => !win.isDestroyed());
60-
61-
if (!existingWindow) {
62-
createMainWindow();
36+
mainWindow.on('close', (event) => {
37+
logger.info('mainWindow closed');
38+
if (env.isMacOS) {
39+
event.preventDefault();
40+
mainWindow?.hide();
6341
} else {
64-
if (!existingWindow.isVisible()) {
65-
existingWindow.show();
66-
}
67-
existingWindow.focus();
42+
mainWindow = null;
6843
}
6944
});
7045

71-
mainWindow.on('closed', () => {
72-
mainWindow = null;
73-
});
74-
7546
return mainWindow;
7647
}
7748

@@ -111,8 +82,14 @@ export function createSettingsWindow(
11182
showInBackground,
11283
});
11384

114-
settingsWindow.on('closed', () => {
115-
settingsWindow = null;
85+
settingsWindow.on('close', (event) => {
86+
if (env.isMacOS) {
87+
event.preventDefault();
88+
settingsWindow?.hide();
89+
} else {
90+
settingsWindow = null;
91+
}
92+
11693
// if mainWindow is not visible, show it
11794
if (mainWindow?.isMinimized()) {
11895
mainWindow?.restore();
@@ -131,7 +108,6 @@ export function createSettingsWindow(
131108
export async function closeSettingsWindow() {
132109
if (settingsWindow) {
133110
settingsWindow.close();
134-
settingsWindow = null;
135111
}
136112
}
137113

@@ -169,7 +145,9 @@ export async function hideWindowBlock<T>(
169145
return result;
170146
} finally {
171147
mainWindow?.setContentProtection(false);
172-
mainWindow?.setAlwaysOnTop(false);
148+
setTimeout(() => {
149+
mainWindow?.setAlwaysOnTop(false);
150+
}, 100);
173151
// restore mainWindow
174152
if (mainWindow && originalBounds) {
175153
mainWindow?.setBounds(originalBounds);

src/preload/index.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type { UTIOPayload } from '@ui-tars/utio';
99

1010
import type { AppState, LocalStore } from '@main/store/types';
1111

12-
export type Channels = 'ipc-example';
12+
export type Channels = '';
1313

1414
const electronHandler = {
1515
ipcRenderer: {
@@ -31,12 +31,6 @@ const electronHandler = {
3131
ipcRenderer.once(channel, (_event, ...args) => func(...args));
3232
},
3333
},
34-
// Add window controls
35-
windowControls: {
36-
minimize: () => ipcRenderer.invoke('minimize-window'),
37-
maximize: () => ipcRenderer.invoke('maximize-window'),
38-
close: () => ipcRenderer.invoke('close-window'),
39-
},
4034
utio: {
4135
shareReport: (params: UTIOPayload<'shareReport'>) =>
4236
ipcRenderer.invoke('utio:shareReport', params),

src/renderer/index.html

+29-1
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,38 @@
4141
body {
4242
overflow: hidden;
4343
}
44+
45+
@keyframes spin {
46+
0% { transform: rotate(0deg); }
47+
100% { transform: rotate(360deg); }
48+
}
49+
50+
.loading-spinner {
51+
display: inline-block;
52+
width: 30px;
53+
height: 30px;
54+
border: 3px solid rgba(0, 0, 0, 0.1);
55+
border-radius: 50%;
56+
border-top-color: #767676;
57+
animation: spin 1s ease-in-out infinite;
58+
margin: 20px;
59+
}
60+
61+
.loading-container {
62+
display: flex;
63+
justify-content: center;
64+
align-items: center;
65+
height: 100vh;
66+
}
67+
4468
</style>
4569
</head>
4670
<body>
47-
<div id="root"></div>
71+
<div id="root">
72+
<div class="loading-container">
73+
<div class="loading-spinner"></div>
74+
</div>
75+
</div>
4876
<script type="module" src="/src/main.tsx"></script>
4977
</body>
5078
</html>

src/renderer/src/components/ChatInput/index.tsx

+5-7
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ const ChatInput = forwardRef((_props, _ref) => {
263263
await api.clearHistory();
264264
};
265265

266+
const stopRun = async () => {
267+
await api.stopRun();
268+
};
269+
266270
return (
267271
<Box p="4" borderTop="1px" borderColor="gray.200">
268272
<Flex direction="column" h="full">
@@ -389,13 +393,7 @@ const ChatInput = forwardRef((_props, _ref) => {
389393
)}
390394
<Button
391395
variant="tars-ghost"
392-
onClick={
393-
running
394-
? () => {
395-
// dispatch('STOP_RUN')
396-
}
397-
: startRun
398-
}
396+
onClick={running ? stopRun : startRun}
399397
isDisabled={!running && localInstructions?.trim() === ''}
400398
>
401399
{(() => {

src/renderer/src/main.tsx

-7
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,3 @@ import App from './App';
99
const container = document.getElementById('root') as HTMLElement;
1010
const root = createRoot(container);
1111
root.render(<App />);
12-
13-
// calling IPC exposed from preload script
14-
window.electron.ipcRenderer.once('ipc-example', (arg) => {
15-
// eslint-disable-next-line no-console
16-
console.log(arg);
17-
});
18-
window.electron.ipcRenderer.sendMessage('ipc-example', ['ping']);

0 commit comments

Comments
 (0)