다중 윈도우 관리 — 윈도우 풀과 상태 동기화
"에디터, IDE, 브라우저 같은 앱은 여러 윈도우를 동시에 관리해야 한다" — 윈도우 생성, 추적, 상태 동기화, 정리까지 체계적인 관리가 필요합니다.
윈도우 매니저 패턴
class WindowManager {
constructor() {
this.windows = new Map();
this.nextId = 1;
}
create(options = {}) {
const id = this.nextId++;
const win = new BrowserWindow({
width: options.width || 800,
height: options.height || 600,
show: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
},
...options,
});
win.once('ready-to-show', () => win.show());
win.on('closed', () => {
this.windows.delete(id);
this.broadcastWindowList();
});
this.windows.set(id, { win, metadata: options.metadata || {} });
win.loadFile(options.file || 'index.html');
this.broadcastWindowList();
return { id, win };
}
get(id) {
return this.windows.get(id)?.win;
}
getAll() {
return Array.from(this.windows.entries()).map(([id, { win, metadata }]) => ({
id,
title: win.getTitle(),
focused: win.isFocused(),
...metadata,
}));
}
close(id) {
const entry = this.windows.get(id);
if (entry) entry.win.close();
}
closeAll() {
for (const { win } of this.windows.values()) {
win.close();
}
}
focusWindow(id) {
const entry = this.windows.get(id);
if (entry) {
const win = entry.win;
if (win.isMinimized()) win.restore();
win.focus();
}
}
// 모든 윈도우에 윈도우 목록 업데이트 전송
broadcastWindowList() {
const list = this.getAll();
for (const { win } of this.windows.values()) {
if (!win.isDestroyed()) {
win.webContents.send('windows:list', list);
}
}
}
// 특정 윈도우를 제외한 모든 윈도우에 메시지 전송
broadcast(channel, data, excludeId) {
for (const [id, { win }] of this.windows) {
if (id !== excludeId && !win.isDestroyed()) {
win.webContents.send(channel, data);
}
}
}
}
const windowManager = new WindowManager();
IPC 연동
// main.js
ipcMain.handle('window:create', (_event, options) => {
const { id } = windowManager.create(options);
return id;
});
ipcMain.handle('window:list', () => {
return windowManager.getAll();
});
ipcMain.on('window:close', (_event, id) => {
windowManager.close(id);
});
ipcMain.on('window:focus', (_event, id) => {
windowManager.focusWindow(id);
});
// 모든 윈도우에 데이터 브로드캐스트
ipcMain.on('broadcast', (event, channel, data) => {
const senderWin = BrowserWindow.fromWebContents(event.sender);
// 보낸 윈도우를 제외하고 전송
const senderId = Array.from(windowManager.windows.entries())
.find(([_, { win }]) => win === senderWin)?.[0];
windowManager.broadcast(channel, data, senderId);
});
윈도우 타입별 관리
// 다른 종류의 윈도우 생성
function createEditorWindow(filePath) {
return windowManager.create({
file: 'editor.html',
metadata: { type: 'editor', filePath },
width: 1200,
height: 800,
});
}
function createSettingsWindow() {
// 설정 창은 하나만 허용
const existing = windowManager.getAll().find(w => w.type === 'settings');
if (existing) {
windowManager.focusWindow(existing.id);
return;
}
return windowManager.create({
file: 'settings.html',
metadata: { type: 'settings' },
width: 600,
height: 400,
resizable: false,
});
}
function createPreviewWindow(parentId) {
const parent = windowManager.get(parentId);
return windowManager.create({
file: 'preview.html',
metadata: { type: 'preview', parentId },
parent: parent,
width: 600,
height: 800,
});
}
윈도우 간 상태 동기화
// 테마 변경 시 모든 윈도우에 반영
ipcMain.on('theme:change', (_event, theme) => {
store.set('theme', theme);
// 모든 윈도우에 브로드캐스트
windowManager.broadcast('theme:changed', theme);
});
면접 포인트 정리
- 윈도우 매니저 패턴으로 다중 윈도우의 생성/추적/정리를 중앙 관리
broadcast패턴으로 윈도우 간 상태 동기화- 설정 창처럼 한 개만 허용해야 하는 윈도우는 중복 생성 방지 필요
- 윈도우가 닫힐 때 Map에서 참조를 제거하여 메모리 누수 방지
다중 윈도우를 다뤘으면, 다음은 프레임리스 윈도우를 알아봅시다.
댓글 로딩 중...