从 Ubuntu 的“文件”管理器拖一个文件到飞书,鼠标能带着文件图标移动,但松开后没有反应。换成 ChatGPT 和 Chrome,现象也一样。
最终,通过几组本地对照测试,故障范围收敛到了 Nautilus 文件管理器与 Chromium 类应用之间的拖放交互。保存打开的文件夹位置、正常退出并重新启动 Nautilus 后,同一条“文件管理器 → Chrome”路径恢复了正常。
这次没有重装软件,也没有调整输入法配置。下面记录排查过程、恢复方法,以及哪些结论已经得到验证。
1. 现象与环境
问题发生在 2026 年 11 月 10 日。文件是从“文件”管理器窗口中拖出来的,不是从桌面图标拖出来的。
具体表现为:
- 文件能被鼠标拖起,有跟随鼠标移动的图标。
- 拖到飞书、ChatGPT 或 Chrome 后,释放鼠标没有预期效果。
- Chrome 新标签页上能看到拖动图标及复制样式的“+”标记,但没有打开文件。
- 普通点击和文件选择仍可操作,并不是整个鼠标失灵。
当时的软件环境如下:
| 项目 | 本机环境 |
|---|---|
| 系统 | Ubuntu 22.04.5 LTS |
| 桌面 | GNOME,X11 会话 |
| GNOME Shell | 42.9-0ubuntu2.4 |
| 文件管理器 | Nautilus 1:42.6-0ubuntu2 |
| GTK 3 软件包 | 3.24.33-1ubuntu2.2 |
| Chrome | 149.0.7827.155 |
| 飞书 | 7.22.9-0 |
| 旧 Nautilus 进程运行时间 | 约 62 天 |
长时间运行是一个值得记录的条件,但它本身不能证明故障由运行时间触发。
2. 为什么不能只看鼠标图标
拖动图标出现,说明拖动已经开始;它不能证明目标应用接收到了文件。
为了定位问题,可以把这次交互拆成几个观察点:
1
2
3
4
5
6
7
8
9
文件管理器开始拖动
↓
向目标应用提供可用的数据类型
↓
目标应用获取文件地址或其他数据
↓
用户释放鼠标,完成放置
↓
目标输入框或网页处理文件
其中任一环节异常,都可能表现为“文件拖过去了,但是没反应”。因此,需要同时观察拖动源、接收端和最终输入结果。
Chrome 新标签页也不是理想的测试目标:它不能直观显示浏览器是否收到拖放事件。换成一个明确接受拖放、能显示事件结果的本地网页,判断会更直接。
3. 先检查桌面和进程状态
在当前图形桌面会话的终端中,可以先执行:
1
2
3
echo "$XDG_SESSION_TYPE"
ps -eo pid,ppid,uid,stat,etimes,comm | \
rg -i 'Xorg|wayland|gnome-shell|nautilus|feishu|ChatGPT'
本机仍然是 X11;Nautilus、飞书和 ChatGPT 都以当前普通用户运行。没有发现“文件管理器以 root 身份启动、目标应用以普通用户运行”这一类明显的运行身份差异。
随后检查近期日志:
1
2
journalctl --user --since '2 hours ago' --no-pager -o short-iso | \
rg -i 'xdnd|drag|drop|nautilus|mutter|JS ERROR'
日志里没有直接解释本次失败的拖放错误。虽然出现过鼠标丢失输入事件的记录,但后面的成功拖放对照表明,不能据此把当前故障直接归因于鼠标硬件。
也检查了窗口的 X11 属性。文件管理器与目标应用窗口都声明了 XdndAware,所以没有证据表明某个目标窗口完全未声明拖放支持。不过,声明支持并不等于协议交互一定成功。
4. 第一组测试:文件管理器能否发出文件地址
先打开一个独立的 GTK 测试窗口,只接受文件 URI,不上传、不移动文件,也不读取文件内容。
从文件管理器拖入一个普通文件后,窗口显示:
1
2
已收到文件地址:1 个
文件管理器到 GTK 的拖放链路可用。
对应日志包含:
1
2
3
4
5
6
7
8
9
10
11
DRAG_ENTER targets=(
'x-special/gnome-icon-list',
'text/uri-list',
'UTF8_STRING',
'COMPOUND_TEXT',
'TEXT',
'STRING',
'text/plain;charset=utf-8',
'text/plain'
)
DATA_RECEIVED target=text/uri-list uri_count=1
这组结果说明,文件管理器能够发起拖动,提供标准的 text/uri-list,而且 GTK 接收端能取得文件地址。
此时可以缩小范围,但还不能宣称文件管理器完全正常。它与 GTK 应用的交互成功,不代表它与 Chromium 应用的交互也一定成功。
5. 第二组测试:Chrome 实际收到了什么
为了排除业务网页本身的影响,在 Chrome 中打开了一个完全本地运行的拖放诊断页。
页面监听 dragenter、dragover 和 drop,并在收到 drop 后显示文件数量。核心测试逻辑如下,可保存为 drop-test.html,再用 Chrome 打开:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!doctype html>
<html lang="zh-CN">
<meta charset="utf-8">
<title>本地文件拖放测试</title>
<style>
body { max-width: 800px; margin: 48px auto; font: 20px sans-serif; }
#drop { border: 3px dashed #5582bf; padding: 64px; background: #f4f8ff; }
pre { white-space: pre-wrap; background: #eee; padding: 20px; }
</style>
<h1>本地文件拖放测试</h1>
<p>只显示事件和文件数量,不上传、不读取文件内容。</p>
<div id="drop">把文件拖到这里</div>
<pre id="result">等待拖放事件……</pre>
<script>
const result = document.querySelector('#result');
document.addEventListener('dragenter', event => {
event.preventDefault();
result.textContent = '收到 dragenter,类型:' +
[...event.dataTransfer.types].join(', ');
});
document.addEventListener('dragover', event => {
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
});
document.addEventListener('drop', event => {
event.preventDefault();
result.textContent = '收到 drop,文件数量:' +
event.dataTransfer.files.length;
});
</script>
</html>
从原来的文件管理器拖入文件,页面停留在:
1
收到 dragenter,类型:text/plain
松开鼠标后,没有出现 drop 结果。
这说明 Chrome 页面已经感知到拖动进入,但它暴露给网页的数据类型只有 text/plain,没有预期的 Files。本次交互没有完成正常的文件放置。
这里必须区分两个观察层次:GTK 日志看到的是拖动源提供的类型;网页看到的是浏览器处理后暴露的类型。不能只凭这两个输出就断言具体是哪个组件“把文件转换成了文字”,还需要对照实验。
6. 第三组测试:换一个拖动源,Chrome 是否能接收
在 GTK 测试窗口底部增加一个可以拖动的区域。这个区域提供一个自动创建的本地测试文件,并且只提供 text/uri-list 类型。
这次拖动路径变成:
1
独立 GTK 测试窗口 → Chrome 本地测试页
测试窗口记录到 Chrome 请求文件地址:
1
2
3
SOURCE_DRAG_BEGIN
SOURCE_DATA_REQUESTED target=text/uri-list
SOURCE_DRAG_END
Chrome 页面最终显示:
1
收到 drop,文件数量:1
到这里,三组对照结果已经明确:
| 拖动源 | 接收端 | 结果 |
|---|---|---|
| 原 Nautilus 进程 | GTK 测试窗口 | 成功收到文件 URI |
| 原 Nautilus 进程 | Chrome 本地测试页 | 只有 dragenter,类型为 text/plain,没有 drop |
| 独立 GTK 测试窗口 | 同一个 Chrome 测试页 | 成功收到 drop,文件数量为 1 |
因此,Chrome 的文件接收能力仍然可用。异常范围进一步收敛到了原 Nautilus 进程与 Chromium 类接收端之间的交互。
7. 恢复操作:保存位置,重启文件管理器
确认上述差异后,选择只重启 Nautilus,并保留当前打开的文件夹位置。
7.1 检查是否有文件操作正在进行
重启前检查了 Nautilus 的 org.gtk.Application.Busy,当时为 false:
1
2
3
4
5
gdbus call --session \
--dest org.gnome.Nautilus \
--object-path /org/gnome/Nautilus \
--method org.freedesktop.DBus.Properties.Get \
org.gtk.Application Busy
实际操作前,也应确认窗口中没有正在复制、移动或解压的任务。Busy 是辅助状态,不应作为所有文件操作都已结束的唯一保证。
7.2 记录当前打开的文件夹
本机 Nautilus 提供了 OpenWindowsWithLocations 属性,可以查询窗口和文件夹 URI 的对应关系:
1
2
3
4
5
gdbus call --session \
--dest org.freedesktop.FileManager1 \
--object-path /org/freedesktop/FileManager1 \
--method org.freedesktop.DBus.Properties.Get \
org.freedesktop.FileManager1 OpenWindowsWithLocations
本次共保存了 4 个窗口对应的位置。这能恢复文件夹位置,但不应理解为完整保存了窗口布局、选中文件和所有界面状态。
7.3 正常退出并重新打开
对于手工操作,确认没有文件操作进行后,可以在桌面终端执行:
1
nautilus --quit
然后重新从应用菜单打开“文件”,或打开一个指定目录:
1
nautilus --new-window "$HOME/Downloads"
目录应替换成实际存在的位置。中文桌面环境的下载目录可能不是 Downloads。
这次通过诊断会话执行 nautilus --quit 时,命令返回了非零状态,但后续检查发现旧进程已经退出。因此,没有仅凭退出码判定重启失败,也没有继续强制结束进程,而是检查实际 PID 和桌面会话接口。
之后通过 org.freedesktop.FileManager1.ShowFolders 重新打开保存的位置,并确认 4 个文件夹位置已经恢复。由于窗口打开是异步过程,第一次立即查询曾显示 0 个位置,稍后再次查询才得到 4 个;检查实际状态时也需要考虑这一点。
7.4 复测原始路径
完成重启后,再从重新打开的文件管理器拖文件到同一个 Chrome 本地测试页,结果变成:
1
收到 drop,文件数量:1
这组复测与之前的失败使用相同的目标页面,主要改变的是 Nautilus 进程。它支持“原 Nautilus 进程的运行状态与故障有关”这一判断。
8. 已确认的原因与尚未确认的部分
本次可以确认到的故障层次是:旧 Nautilus 进程与 Chromium 类应用之间的文件拖放交互异常,更换 Nautilus 进程后,Chrome 的原始拖放路径恢复。
已经验证的事实包括:
- 鼠标可以发起拖动,GTK 接收端也可以收到文件 URI。
- 同一个 Chrome 测试页可以接收独立 GTK 拖动源提供的文件。
- 旧 Nautilus 拖入 Chrome 时,只观察到
text/plain类型的dragenter,没有完成drop。 - 重启 Nautilus 后,Chrome 收到了文件类型的放置结果。
尚未查明的是:
- Nautilus 的哪一项内部状态导致了异常。
- 是否与数据类型选择、拖放动作协商或其他 X11 交互细节有关。
- 是否存在特定的触发操作,或者能稳定复现的上游缺陷。
- 连续运行约 62 天是否与故障存在因果关系。
“重启后恢复”是恢复手段和定位证据,还不是代码级根因证明。本次没有记录完整的 X11 拖放协议交互,也没有对 Nautilus 或 Chromium 做调用栈追踪,因此不宜把某种内部机制写成确定原因。
此前这台机器还处理过搜狗输入法切换问题。本次恢复过程中没有修改输入法设置,没有证据表明两次故障有关。
另外,本次闭环验证的是 Chrome。飞书和 ChatGPT 最初有同类现象,但在本次记录结束时,尚未获得它们各自恢复的实际测试结果,不能将三者一概写为全部修复。
9. 再次遇到时的排查顺序
- 确认文件是从桌面、文件管理器、压缩包还是远程目录拖出。
- 区分“拖不起来”和“拖起来但目标没反应”。
- 用明确支持文件拖放的本地页面测试,记录事件类型和文件数量。
- 用独立接收端验证源应用能否提供文件 URI。
- 换一个拖动源,检查目标应用的文件接收功能是否可用。
- 如果故障收敛到文件管理器,先记录窗口位置并确认文件操作结束,再正常重启文件管理器。
- 重启后复测最初失败的路径,并对每个受影响应用分别确认。
对于这次问题,最有价值的证据不是某条报错日志,而是三个对照测试加上重启后的复测。它们把“整个系统不能拖文件”缩小到了一个具体的进程交互问题,也让恢复操作能够只涉及文件管理器。