Ubuntu 下 Flameshot 截图一直闪屏,已找到问题并解决

Ubuntu 下 Flameshot 截图一直闪屏,已找到问题并解决

昨天还在正常用 Flameshot,今天重启电脑后,一进入截图界面,屏幕就开始不停地闪,按 Esc 退出才恢复。

最后解决了,桌面也保留在 125% 缩放。

把过程记一下,遇到相同问题的朋友可以参考。

一开始查错了方向

我的系统是 Ubuntu 22.04.5,GNOME 桌面,用的是 X11。Flameshot 版本是 11.0.0,笔记本有核显和 NVIDIA 独显。

最初怀疑是显卡的问题,去 NVIDIA Settings 里找 Allow Flipping,结果连网上说的 X Screen 0 都没有。后来确认机器处于 on-demand 模式,屏幕由核显负责显示,独显按需使用,这条路就先放下了。

接着重启了 GNOME Shell,又用一份临时配置启动 Flameshot,还是闪。调整 Qt 的自动缩放变量也没用。

真正有用的是一个很简单的测试:把桌面缩放从 125% 改成 100%。

不闪了。

但我的屏幕是 2560 × 1600,100% 下的字和窗口太小,看着费劲。总不能每次截图前都去改一遍缩放。

日志里能看到它在反复切换尺寸

检查显示状态用的是这几条命令:

bash 复制代码
echo "$XDG_CURRENT_DESKTOP / $XDG_SESSION_TYPE"
xrandr --current
xrandr --verbose
gsettings get org.gnome.mutter experimental-features

系统开启了 x11-randr-fractional-scaling。125% 缩放时,桌面的虚拟尺寸是 4096 × 2560;闪屏期间,Xorg 日志一直重复这两行:

text 复制代码
modeset(0): Allocate new frame buffer 2560x1600 stride
modeset(0): Allocate new frame buffer 4096x2560 stride

这里变的是画面缓冲区尺寸。屏幕面板还是原来的分辨率,只是桌面内部的画面尺寸在来回切换。

GitHub 上也有类似的报告:125% 下截图持续闪烁,100% 下正常。Flameshot 的 FAQ 则提到了 Qt 在分数缩放和全屏应用上的兼容问题。

到这里,排查方向就转到了截图窗口和桌面合成的处理上。至于为什么昨天没事、重启后才出现,目前还没查清。

保留 125%,只处理 Flameshot 窗口

这次有效的办法,是给截图窗口加上这个属性:

text 复制代码
_NET_WM_BYPASS_COMPOSITOR = 2

按 EWMH 规范,2 表示请求这个窗口继续经过合成器处理。在我的环境里,加上后就不再反复切换画面尺寸了。

中间还有个小插曲:第一次改完确实不闪了,但我自己重新输入 flameshot gui,又开始闪。

原因是刚才只改了那一个窗口。下一次截图会创建新窗口,之前的属性自然就没了。

所以最后用了一个 Python 脚本,监听新显示的窗口,遇到 Flameshot 的截图覆盖窗口,就自动设置这个属性。这样托盘、快捷键和原来的命令都能照常用。

下面是实际用的脚本。保存到 ~/.local/bin/flameshot-compositor-workaround,目录不存在就先创建:

bash 复制代码
mkdir -p "$HOME/.local/bin"
python 复制代码
#!/usr/bin/python3
"""Keep Flameshot capture overlays composited on GNOME X11 fractional scaling.

GNOME can otherwise repeatedly switch the framebuffer size while the overlay
is visible. This changes only the overlay's _NET_WM_BYPASS_COMPOSITOR hint.
"""
import fcntl
import os
import sys
from pathlib import Path
from Xlib import X, Xatom, display, error

if os.environ.get('XDG_SESSION_TYPE') != 'x11':
    sys.exit(0)
runtime = os.environ.get('XDG_RUNTIME_DIR')
if not runtime:
    sys.exit('XDG_RUNTIME_DIR is unavailable')
lock = open(Path(runtime) / 'flameshot-compositor-workaround.lock', 'w')
try:
    fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
except BlockingIOError:
    sys.exit(0)
connection = display.Display()
connection.set_error_handler(lambda *_: None)
root = connection.screen().root
hint = connection.intern_atom('_NET_WM_BYPASS_COMPOSITOR')
root.change_attributes(event_mask=X.SubstructureNotifyMask)
connection.sync()

def keep_composited(window):
    try:
        cls = window.get_wm_class() or ()
        if not any(s.lower() == 'flameshot' for s in cls):
            return
        if not window.get_attributes().override_redirect:
            return
        prop = window.get_full_property(hint, Xatom.CARDINAL)
        if prop is None or list(prop.value) != [2]:
            window.change_property(hint, Xatom.CARDINAL, 32, [2])
            connection.flush()
    except (error.XError, error.DisplayError):
        pass

for window in root.query_tree().children:
    keep_composited(window)
connection.flush()
while True:
    event = connection.next_event()
    if event.type == X.MapNotify:
        keep_composited(event.window)

脚本依赖 python-xlib。可以先检查一下:

bash 复制代码
/usr/bin/python3 -c 'from Xlib import display'

如果提示找不到 Xlib,Ubuntu 下安装 python3-xlib:

bash 复制代码
sudo apt install python3-xlib

在桌面的终端里启动它:

bash 复制代码
nohup /usr/bin/python3 "$HOME/.local/bin/flameshot-compositor-workaround" \
  > /tmp/flameshot-compositor-workaround.log 2>&1 < /dev/null &

然后再试 flameshot gui。记得退出截图后多开几次,也试试屏幕边缘的框选,确认新窗口都正常。

加上自启动,以后不用手动管

确认有效后,再加一个登录自启动项:

bash 复制代码
mkdir -p "$HOME/.config/autostart"
cat > "$HOME/.config/autostart/flameshot-compositor-workaround.desktop" <<EOF
[Desktop Entry]
Type=Application
Name=Flameshot fractional scaling workaround
Exec=/usr/bin/python3 "$HOME/.local/bin/flameshot-compositor-workaround"
TryExec=/usr/bin/python3
Terminal=false
NoDisplay=true
X-GNOME-Autostart-enabled=true
EOF

我这边连续重新打开了三次截图,日志里没有再出现尺寸切换,实际框选也正常。现在桌面还是 125%,不用为了截图把整个界面调小。

这个办法只在我这套 GNOME + X11 环境里验证过,是绕过兼容问题的处理。Wayland 不适用,脚本检测到 Wayland 会直接退出。

如果以后升级后不再需要它,删除脚本和自启动项,再注销登录即可:

bash 复制代码
rm "$HOME/.local/bin/flameshot-compositor-workaround"
rm "$HOME/.config/autostart/flameshot-compositor-workaround.desktop"
相关推荐
进击的荆棘1 小时前
Linux系统——进程信号之保存和捕捉信号
linux·运维·服务器·信号处理·信号
whyutianict_vv3 小时前
云计算 HCIE 认证体系解析:HCIA/HCIP/HCIE 三级科目与知识边界
linux·运维·云计算
0+11110 小时前
Linux --从 poll 到 epoll多路转接
linux·服务器·1024程序员节
青瓦梦滋10 小时前
WebSocket协议
linux·服务器·网络·c++·websocket·网络协议·http
2601_9498477513 小时前
bcrypt.js 跨端三方库仓颉适配全流程
linux·运维·ubuntu
m0_6399069413 小时前
Linux 操作系统入门:目录结构、服务排查常用命令、Shell 脚本基础
linux·运维·后端
水饺编程15 小时前
第2章:Linux 基础,exit 命令
linux·c语言·汇编
木子欢儿15 小时前
Debian 13 + vsftpd 搭建FTP服务
linux·服务器·前端·网络·debian
GeW16 小时前
新质生产力落地实践:企业级Linux迁移与数据库国产化
linux