[Bug] Linux 下托盘图标右键菜单无法展开(popUpContextMenu 在 Linux 无效,需改用 setContextMenu)

Author: unknown-geziCreated Sep 26, 2026Updated Sep 28, 2026
LabelsBugGood first issueknown issues
  • 你是否在现有 Issue列表 中搜索过相同问题,但未找到?

说明:已检索 托盘 / tray / menu / right-click 等关键词。 #472 是「KDE 托盘增加退出按钮」的功能请求,#667 是「root 权限启动的兼容性问题」,均与本问题不同。

Ⅰ. 请说明操作系统及DS的版本号:

  1. 操作系统:Debian GNU/Linux 13 (trixie) amd64,桌面环境 Cinnamon 6.4.10,X11 会话
  2. DS版本号:2.2.0(Debian 包 DevSidecar-2.2.0-linux-x86_64.deb,内置 Electron 41.3.0 / Chrome 146.0.7680.188)

Ⅱ. 问题描述:

在 Linux 下,右键点击系统托盘的 DS 图标不会弹出任何菜单,DevTools (F12) 与 退出 两项都看不到(左键单击可以正常显示主窗口)。

经排查,这不是用户配置或桌面环境的问题,而是 packages/gui/src/background.js 中 setTray() 的实现 bug:

javascript
// packages/gui/src/background.js  (master)
// 第 184~188 行
appTray.on('right-click', () => {
  setTimeout(() => {
    appTray.popUpContextMenu(contextMenu)
  }, 200)
})

全部菜单都是通过 popUpContextMenu() 弹出的,但 Electron 官方文档明确标注该方法仅支持 macOS 和 Windows:

tray.popUpContextMenu([menu, position]) macOS Windows

tray.setContextMenu(menu)

Sets the context menu for this icon.

(来源:Electron 官方 docs/api/tray.md)

因此该调用在 Linux 上是静默失效的(不报错、无日志)。而 Linux 下必须通过 appTray.setContextMenu(contextMenu) 把菜单注册到托盘项,Electron 才会经由 com.canonical.dbusmenu 导出菜单。

补充:setContextMenu 一次都没有被调用过——全仓库检索 setContextMenu 出现次数为 0,popUpContextMenu 为 1。

实测证据(DBus 层)

修复前,托盘项虽然注册成功,但导出的 dbusmenu 子项为空,所以桌面环境拿不到任何菜单项:

bash
$ gdbus call --session --dest org.kde.StatusNotifierWatcher \
    --object-path /StatusNotifierWatcher \
    --method org.freedesktop.DBus.Properties.Get \
    org.kde.StatusNotifierWatcher RegisteredStatusNotifierItems
(<[':1.66/StatusNotifierItem',
   ':1.124/StatusNotifierItem',                       <-- dev-sidecar
   'org.freedesktop.StatusNotifierItem-10779-1/StatusNotifierItem']>,)

$ dbus-send --session --print-reply --dest=:1.124 /com/canonical/dbusmenu \
    com.canonical.dbusmenu.GetLayout int32:0 int32:-1 array:string:
   uint32 0
   struct {
      int32 0
      array [
         dict entry(
            string "children-display"
            variant  string "submenu"
         )
      ]
      array [
      ]                          <-- children 为空,没有任何菜单项!
   }

注意 Menu 属性其实是有值的(objectpath '/com/canonical/dbusmenu'),只是里面没有任何条目,因此表现为"点了没反应"。

修复后对比(仅加了一个 setContextMenu 调用)

bash
$ dbus-send --session --print-reply --dest=:1.175 /com/canonical/dbusmenu \
    com.canonical.dbusmenu.GetLayout int32:0 int32:-1 array:string:
   uint32 0
   struct {
      int32 0
      array [ string "children-display" -> "submenu" ]
      array [
         struct { int32 1  [ label -> "DevTools (F12)" ]  [] }   <-- 出现了
         struct { int32 2  [ label -> "退出" ]            [] }   <-- 出现了
      ]
   }

同时用 X11 合成事件真实右键托盘图标,弹出的菜单区域稳定存在(把鼠标移开后菜单仍保持显示,点击别处才消失),确认菜单可以正常展开、也可以正常点击。

Ⅲ. 期望的结果:

  1. Linux 下右键托盘图标能正常弹出 DevTools (F12) / 退出 菜单。
  2. setTray() 按平台分流:Linux 使用 setContextMenu(),macOS / Windows 保持原有 popUpContextMenu() 行为不变。

建议改法(packages/gui/src/background.js):

javascript
  // 图标的上下文菜单
  const contextMenu = Menu.buildFromTemplate(trayMenuTemplate)

  // 设置托盘悬浮提示
  appTray.setToolTip('DevSidecar-开发者边车辅助工具')
  // 单击托盘小图标显示应用
  appTray.on('click', () => {
    // 显示主程序
    showWin()
  })

-  appTray.on('right-click', () => {
-    setTimeout(() => {
-      appTray.popUpContextMenu(contextMenu)
-    }, 200)
-  })
+  if (isLinux) {
+    // Linux 必须把菜单注册到托盘项,右键菜单才能展开;
+    // popUpContextMenu() 仅支持 macOS/Windows,在 Linux 下无效。
+    appTray.setContextMenu(contextMenu)
+  } else {
+    appTray.on('right-click', () => {
+      setTimeout(() => {
+        appTray.popUpContextMenu(contextMenu)
+      }, 200)
+    })
+  }

  return appTray

isLinux 在该文件第 16 行已定义(const isLinux = process.platform === 'linux'),无需新增变量。

附注:Linux + libappindicator/StatusNotifierItem 的机制下,菜单注册后通常左右键都会弹出菜单,原本 appTray.on('click') → showWin() 的"左键显示主窗口"可能被桌面环境接管。这点建议作者按实际预期取舍;若希望保留"左键显示窗口",可同时在菜单里补一个「显示主窗口」项。

Ⅳ. 如何复现问题?

  1. 在 Linux(实测 Debian 13 + Cinnamon 6.4.10 / X11)安装 DevSidecar-2.2.0-linux-x86_64.deb 并启动。
  2. 确认系统托盘出现 DS 图标(图标本身显示正常)。
  3. 用鼠标右键点击该托盘图标。
  4. 观察结果:不会弹出任何菜单。

命令行复核方式:

bash
# 1. 找到 dev-sidecar 的 SNI 总线名(用它的 PID 对上)
gdbus call --session --dest org.kde.StatusNotifierWatcher \
  --object-path /StatusNotifierWatcher \
  --method org.freedesktop.DBus.Properties.Get \
  org.kde.StatusNotifierWatcher RegisteredStatusNotifierItems

# 2. 查看该托盘项导出的菜单布局
dbus-send --session --print-reply --dest=:1.xxx /com/canonical/dbusmenu \
  com.canonical.dbusmenu.GetLayout int32:0 int32:-1 array:string:
#   修复前:children 为空数组 []
#   修复后:children 含 "DevTools (F12)" 与 "退出"

影响范围推测:由于是跨平台的 Electron API 用法问题,理论上所有 Linux 桌面环境(GNOME / KDE / Cinnamon / XFCE 等)都存在该问题,欢迎其他发行版用户补充验证。

Ⅴ. 请提供相关的错误日志,尽可能的详细:(日志文件在 ${user.home}/.dev-sidecar/logs/ 目录下)

本问题没有任何报错日志,这正是它容易被忽略的原因——popUpContextMenu() 在 Linux 上是静默 no-op,core.log / gui.log / server.log 中都不会留下任何痕迹。日志中仅能看到托盘创建成功、代理服务正常启动:

点击查看日志
log
[2026-09-26T18:05:16.xxx] [INFO] gui  - background.js start, platform is linux
[2026-09-26T18:05:19.xxx] [INFO] core - 开启系统代理成功:127.0.0.1:31181
[2026-09-26T18:05:19.xxx] [INFO] core - status changed: { key: 'server.enabled', value: true }

(托盘创建、菜单构建均无任何 ERROR / WARN,符合"静默失效"的特征。)

Ⅵ. 有必要时,请提供 ${user.home}/.dev-sidecar/running.json 文件内容:

与配置无关,~/.dev-sidecar/config.json 为默认配置(不存在该文件),本问题在全新安装、未做任何自定义配置的情况下即可复现。

点击查看运行参数
json
{
  "note": "本问题与配置无关,全新安装即可复现;此处省略 running.json 全文。",
  "app": { "mode": "default" },
  "server": { "enabled": true, "host": "127.0.0.1", "port": 31181 }
}

给维护者的补充信息

  • 本地验证环境:Debian 13 (trixie)、Cinnamon 6.4.10、X11、Electron 41.3.0。
  • 本地采用的最小改动:仅修改 resources/app.asar 内的 src/background.js(对应源码 packages/gui/src/background.js),其余 20928 个归档文件字节完全一致(已逐个校验 SHA256)。
  • 改动后 node --check 语法校验通过;代理服务、系统代理、根证书、开机自启等功能均无回归。
  • 如果作者需要,我可以补一个 PR。