lobehub/.agents/skills/desktop/references/window-management.md
Innei 346fc4617e
♻️ refactor: migrate AI Rules to Claude Code Skills (#11737)
♻️ refactor: migrate AI Rules to Claude Code Skills system

Migrate all AI Rules from .cursor/rules/ to .agents/skills/ directory:
- Move 23 skills to .agents/skills/ (main directory)
- Update symlinks: .claude/skills, .cursor/skills, .codex/skills
- Create project-overview skill from project documentation
- Add references/ subdirectories for complex skills
- Remove LobeChat references from skill descriptions
- Delete obsolete .cursor/rules/ and .claude/commands/prompts/ directories

Skills structure enables better portability and maintainability across AI tools.
2026-01-23 22:30:18 +08:00

3.3 KiB

Desktop Window Management Guide

Window Management Overview

  1. Window creation and configuration
  2. Window state management (size, position, maximize)
  3. Multi-window coordination
  4. Window event handling

File Structure

apps/desktop/src/main/
├── appBrowsers.ts              # Core window management
├── controllers/
│   └── BrowserWindowsCtr.ts    # Window controller
└── modules/
    └── browserWindowManager.ts # Window manager module

Window Creation

export const createMainWindow = () => {
  const mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    minWidth: 600,
    minHeight: 400,
    webPreferences: {
      preload: path.join(__dirname, '../preload/index.js'),
      contextIsolation: true,
      nodeIntegration: false,
    },
  });

  if (isDev) {
    mainWindow.loadURL('http://localhost:3000');
  } else {
    mainWindow.loadFile(path.join(__dirname, '../../renderer/index.html'));
  }

  return mainWindow;
};

Window State Persistence

const saveWindowState = (window: BrowserWindow) => {
  if (!window.isMinimized() && !window.isMaximized()) {
    const [x, y] = window.getPosition();
    const [width, height] = window.getSize();
    settings.set('windowState', { x, y, width, height });
  }
};

const restoreWindowState = (window: BrowserWindow) => {
  const state = settings.get('windowState');
  if (state) {
    window.setBounds({ x: state.x, y: state.y, width: state.width, height: state.height });
  }
};

window.on('close', () => saveWindowState(window));

Multi-Window Management

export class WindowManager {
  private windows: Map<string, BrowserWindow> = new Map();

  createWindow(id: string, options: BrowserWindowConstructorOptions) {
    const window = new BrowserWindow(options);
    this.windows.set(id, window);
    window.on('closed', () => this.windows.delete(id));
    return window;
  }

  getWindow(id: string) {
    return this.windows.get(id);
  }
}

Window IPC Controller

// apps/desktop/src/main/controllers/BrowserWindowsCtr.ts
export default class BrowserWindowsCtr extends ControllerModule {
  static override readonly groupName = 'windows';

  @IpcMethod()
  minimizeWindow() {
    BrowserWindow.getFocusedWindow()?.minimize();
    return { success: true };
  }

  @IpcMethod()
  maximizeWindow() {
    const win = BrowserWindow.getFocusedWindow();
    win?.isMaximized() ? win.restore() : win?.maximize();
    return { success: true };
  }
}

Renderer Service

// src/services/electron/windowService.ts
import { ensureElectronIpc } from '@/utils/electron/ipc';

const ipc = ensureElectronIpc();

export const windowService = {
  minimize: () => ipc.windows.minimizeWindow(),
  maximize: () => ipc.windows.maximizeWindow(),
  close: () => ipc.windows.closeWindow(),
};

Frameless Window

const window = new BrowserWindow({
  frame: false,
  titleBarStyle: 'hidden',
});
.titlebar { -webkit-app-region: drag; }
.titlebar-button { -webkit-app-region: no-drag; }

Best Practices

  1. Use show: false initially, show after content loads
  2. Always set secure webPreferences
  3. Handle webContents.on('crashed') for recovery
  4. Clean up resources on window.on('closed')