# Gpui App

> 从零搭建 gpui / gpui-component 桌面应用的起步模板。涵盖 Cargo.toml git 依赖(gpui + gpui_platform + gpui-component)、main.rs 入口(application().run / open_window / Root)、资产与图标注册、WindowOptions、退出与激活。创建新 gpui 项目、初始化工程、写 main.rs 或配置依赖时使用。

- Skill: `zerx-lab/gpui-app` (Agent Skill)
- Install (CLI): `npx skillmds@latest add zerx-lab/gpui-app`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zerx-lab/gpui-app/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: zerx-lab (https://skillmd.com/u/zerx-lab)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zerx-lab/gpui-app

---


# gpui 应用起步模板

以下内容按 zed 主干 gpui(0.2.x)与 gpui-component 0.5.x 源码核实(zed `crates/gpui/examples/hello_world.rs`、gpui-component `examples/hello_world`)。

## 1. Cargo.toml

gpui 不发布 crates.io 正式版,统一用 git 依赖;**gpui_platform 必须一并引入**(平台后端 + 入口函数):

```toml
[package]
name = "my-app"
version = "0.1.0"
edition = "2024"

[dependencies]
gpui = { git = "https://github.com/zed-industries/zed" }
gpui_platform = { git = "https://github.com/zed-industries/zed", features = ["font-kit"] }
# Linux 需要窗口系统后端时:features = ["font-kit", "x11", "wayland"]

# 用组件库时再加:
gpui-component = { git = "https://github.com/longbridge/gpui-component" }
gpui-component-assets = { git = "https://github.com/longbridge/gpui-component" }  # 图标资产,可选

[profile.dev.package]
# gpui 渲染相关 crate 在 dev 下也开优化,否则明显卡顿(上游同款配置)
gpui = { opt-level = 3 }
gpui_platform = { opt-level = 3 }
taffy = { opt-level = 3 }
resvg = { opt-level = 3 }
rustybuzz = { opt-level = 3 }
ttf-parser = { opt-level = 3 }
```

注意:crate 名 `gpui-component`,导入名 `gpui_component`。若与 gpui-component 同用,两处 git 的 zed 版本由 Cargo 统一解析;编译报 gpui 版本冲突时,以 gpui-component 锁定的 zed rev 为准。

## 2. 纯 gpui 最小应用

```rust
use gpui::{
    App, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions,
    div, prelude::*, px, rgb, size,
};
use gpui_platform::application;

struct HelloWorld {
    text: SharedString,
}

impl Render for HelloWorld {
    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .flex()
            .flex_col()
            .gap_2()
            .size_full()
            .justify_center()
            .items_center()
            .bg(rgb(0x2e7d32))
            .text_color(rgb(0xffffff))
            .child(format!("Hello, {}!", self.text))
    }
}

fn main() {
    application().run(|cx: &mut App| {
        let bounds = Bounds::centered(None, size(px(500.), px(500.)), cx);
        cx.open_window(
            WindowOptions {
                window_bounds: Some(WindowBounds::Windowed(bounds)),
                ..Default::default()
            },
            |_window, cx| cx.new(|_| HelloWorld { text: "World".into() }),
        )
        .unwrap();
        cx.activate(true); // macOS 置前;Windows/Linux 无害
    });
}
```

要点:
- `use gpui::prelude::*;` 必带,否则 `.flex()`/`.child()`/`Render` 等 trait 方法全部找不到(E0599)。
- `open_window` 构建闭包签名 `(&mut Window, &mut App) -> Entity<V>`,必须返回 `cx.new(…)`。
- 入口是 `gpui_platform::application()`;`Application::new()` 已不存在。

## 3. gpui-component 应用(带 Root)

```rust
use gpui::{App, Window, WindowOptions, prelude::*};
use gpui_component::{ActiveTheme as _, Root, button::Button, h_flex};

struct Example;

impl Render for Example {
    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        h_flex()
            .size_full()
            .justify_center()
            .items_center()
            .bg(cx.theme().background)
            .child(Button::new("hi").primary().label("Hello"))
    }
}

fn main() {
    gpui_platform::application()
        // 图标可用的前提:注册资产(或自定义 rust-embed AssetSource)
        .with_assets(gpui_component_assets::Assets)
        .run(move |cx| {
            gpui_component::init(cx); // 必须最先调用

            cx.spawn(async move |cx| {
                cx.open_window(WindowOptions::default(), |window, cx| {
                    let view = cx.new(|_| Example);
                    // 每个窗口第一层视图必须是 Root,否则 Dialog/Sheet/Notification 图层缺失
                    cx.new(|cx| Root::new(view, window, cx).bg(cx.theme().background))
                })
                .expect("Failed to open window");
            })
            .detach();
        });
}
```

三条硬性顺序:`init(cx)` 最先 → 窗口首层 `Root` → 主题访问 `use gpui_component::ActiveTheme as _;` 后 `cx.theme()`。

## 4. 常用 WindowOptions 字段

`window_bounds: Option<WindowBounds>`(`Windowed`/`Maximized`/`Fullscreen`)、`titlebar: Option<TitlebarOptions>`、`focus`、`show`、`kind`、`is_movable`、`is_resizable`、`is_minimizable`、`window_background`、`app_id`、`window_min_size`、`window_decorations`、`icon`。无 `WindowBounds::Fixed`。

## 5. 退出与窗口关闭

窗口关闭默认**不**退出应用,需要"最后窗口关闭即退出"时(已对照 `examples/on_window_close_quit.rs`):

```rust
cx.on_window_closed(|cx, _window_id| {
    if cx.windows().is_empty() {
        cx.quit();
    }
})
.detach();
```

相关:代码里主动关窗用 `window.remove_window()`;绑定快捷键 `cx.bind_keys([KeyBinding::new("cmd-w", CloseWindow, None)])` 配合 `actions!(example, [CloseWindow])` 与元素上的 `.on_action(|_: &CloseWindow, window, _| window.remove_window())`。

## 6. 下一步

- 布局/样式:`skill://gpui/references/layout-style.md`
- 实体与状态:`skill://gpui/references/entity.md`
- 动作与快捷键:`skill://gpui/references/action.md`
- 组件目录:`skill://gpui-component`
- 新旧 API 对照:`skill://gpui-migration`

