我想做一个把任意 App 塞进菜单栏气泡的工具。AI 说:真的做不到,但我们可以假装。于是 BarPin 诞生了。


起因:Cmd+Tab 按烦了

macOS 用户应该都有这个体验——开着七八个 App,Cmd+Tab 按出来一长串图标,眼花缭乱地找半天,才切到想要的那个。

我每天的工作流大概是这样的:写代码 → 切到终端跑一下 → 切到浏览器查文档 → 切到 Obsidian 记个笔记 → 切回 IDE……来来回回,光是”切换”这个动作就消耗了大量注意力。

有一款叫 MenubarX 的 App 给了我灵感——它可以把网页嵌入到菜单栏的气泡里,点一下就弹出来,再点一下就收回去。非常优雅。

我就想:如果不止网页,而是任意 App 都能这样呢?

于是我打开 Codex(OpenAI 的 AI 编程助手),跟它描述了我的想法。


AI 的第一课:学会妥协

我兴致勃勃地告诉 Codex:“我要做一个能把任意 App 的窗口真正嵌入到气泡容器里的工具。”

Codex 很认真地给我分析了三条路线:

简单翻译一下它的结论:

  • 方案一(实时预览):截取窗口画面显示在气泡里——看着像,但点不了
  • 方案二(窗口置顶+遮罩裁切):真的移动窗口过来——半可行,但会打架
  • 方案三(容器化):只支持自己开发的子 App——生态成本太高

最后 Codex 灵魂一问:

你要的是”视觉上像把窗口塞进气泡”,还是”真的能在气泡里操作窗口内容”?如果是前者,我们可以做到很像。

我欣然接受了这个设定。

这其实是 Vibe Coding 最有意思的地方:你提出一个模糊的想法,AI 帮你厘清边界,然后在可行的范围内给你最好的方案。 比起闷头写代码写到一半发现技术路线不通,这种”先聊再做”的方式高效得多。


10 秒看懂 BarPin

先上效果,比我啰嗦半天管用:

BarPin 演示

一句话:点菜单栏图标,App 就弹出来贴在图标下方;再点一下,就收回去。就像原生的菜单栏工具一样。


它到底能干什么

🎯 任意 App 变气泡

不需要 App 本身做任何适配。BarPin 通过 macOS 的 Accessibility API 直接控制外部窗口的位置和大小——你电脑上装的任何 App 都可以被”Pin”到菜单栏。

🔄 智能三态切换

点击菜单栏图标时,BarPin 会自动判断当前状态:

App 状态点击后的行为
在前台(正在用)隐藏窗口
在后台(被遮住了)唤到最前
没有可见窗口重新拉起并定位

一个点击,覆盖所有情况。 不用管 App 现在在哪、是什么状态,点就完了。

📌 窗口贴近菜单栏

BarPin 不是随便弹一个窗口出来——它会精确计算菜单栏图标的位置,把 App 窗口定位在正下方。视觉上就像真的从菜单栏”弹”出来的,有归属感。

📐 窗口大小记忆

每个被 Pin 的 App 独立记住你调整过的窗口尺寸。下次唤起时自动恢复,不用每次都手动拖。

⌨️ 全局热键

每个 Pin 可以绑定独立的快捷键,而且自带冲突检测。摸鱼的时候,老板走过来,一个快捷键收掉,走了再一个快捷键弹出来——丝滑。

🎨 图标可定制

支持在 App 原始图标和 Pin 图标之间切换,灰色/彩色随你选。管理页面可以统一管理所有 Pin 的配置。


使用场景:为什么叫”摸鱼神器”

BarPin 的 Slogan 是**“你的摸鱼神器”**——虽然是个玩笑,但它确实精准地描述了使用体验:

  • Obsidian / Notion → Pin 到菜单栏,随时弹出来记个想法,用完收回去,不占 Dock 位
  • Apple Music / Spotify → 切歌不用离开当前工作,点一下菜单栏就是播放器
  • 终端 / ChatGPT → 写代码时随时呼出查个命令或问个问题,用完即走
  • 微信 / Telegram → 老板发消息了?弹出来看一眼;要专注了?收回去眼不见心不烦

本质上,BarPin 解决的是一个很朴素的问题:有些 App 你需要频繁使用,但不需要它一直占着屏幕。 菜单栏是 macOS 上最随手可及的位置——把它利用起来,就是最自然的交互方式。


Vibe Coding 过程中的趣事

图标的故事

BarPin 这个名字是”Bar”(菜单栏)+ “Pin”(固定)的组合。然后我让 Codex 给画个图标。

它画了这个:

嗯……这是一个红色的图钉。图钉确定不是长这样的吗?📌

好吧,虽然造型奇特了点,但红色圆头+向下的箭头,倒是很直观地传达了”把东西固定到上面”的含义。我接受了。

单文件 1800 行

整个 BarPin 的主程序逻辑写在一个 main.swift 文件里,大约 1800 行。纯 AppKit,不依赖 SwiftUI。

你可能会说”单文件 1800 行太乱了吧”,但对于 Vibe Coding 来说,这其实是一个优势——AI 一次性能看到全部上下文,改起来不用在多个文件间跳来跳去。当项目还在快速迭代阶段,“能跑”比”架构优雅”重要得多。

坐标系翻转的坑

macOS 有一个经典的坑:AppKit 的坐标系原点在左下角(Y 轴向上),但 Accessibility API 和屏幕坐标系的原点在左上角(Y 轴向下)。

这意味着你通过 Accessibility API 获取窗口位置后,不能直接用——得做一次 Y 轴翻转。第一次遇到这个问题时,窗口飞到了屏幕外面,Codex 和我一起 debug 了好一会儿才搞明白。

Carbon API 的执念

注册全局热键用的是 Carbon API——这是一个非常古老的 macOS API,比 Cocoa 还早。但它有一个 NSEvent 全局监听做不到的优势:即使 App 不在前台,也能捕获快捷键事件。 对于一个菜单栏工具来说,这是必须的。

让 AI 用 2026 年的方式写 1990 年代的 API,也算是一种跨时代的浪漫了。


技术概览

给感兴趣的开发者朋友列一下关键技术点:

维度方案
UI 框架纯 AppKit(NSStatusBar + NSWindow)
窗口控制macOS Accessibility API
全局热键Carbon API (RegisterEventHotKey)
图标绘制纯代码 NSBezierPath,零图片资源
构建产物Universal Binary(Intel + Apple Silicon)
语言Swift,SwiftPM 管理

整个项目没有任何第三方依赖,swift run 就能跑。


下载试试

BarPin 完全开源,代码和编译好的 App 都在 GitHub:

👉 github.com/JingkaiTang/BarPin

⚠️ 首次打开提示:由于没有 Apple Developer ID 签名,macOS 会拦截。右键 → 打开,或者在”系统设置 > 隐私与安全性”里点”仍要打开”即可。另外需要授予辅助功能权限(系统设置 > 隐私与安全性 > 辅助功能)。


写在最后

BarPin 是一个典型的 Vibe Coding 产物——从想法到可用的 App,AI 做了绝大部分编码工作,我负责定义需求、把控方向、测试体验。

整个过程最让我感慨的是:AI 不只是会写代码,它还会帮你重新定义问题。 我一开始想做”把窗口嵌入气泡”,这在技术上几乎不可行。但 AI 帮我看清了真正的需求——用户要的不是”嵌入”,而是”随时可达”。围绕这个核心需求,“假装气泡”完全够用,而且体验更好。

有时候,最好的解决方案不是硬刚技术难题,而是换一个角度看问题。


本文源码:BarPin