python - 如何检查之前获得的 GDKWindow 在 GTK+-3 中是否仍然有效?
问题描述
我使用 GDK 库在 GTK+-3 中编写了一个屏幕截图程序,它大部分都可以工作,但我发现有时程序会随机崩溃并出现 X11 错误。我意识到如果立即打开和关闭一个窗口,就会触发崩溃,并且我能够编写以下程序来重现该问题。
from time import sleep
from gi.repository import GLib, Gtk, Gdk
# (Open and select a window before the program starts.)
print("Open your window and focus on it.")
for i in range(5):
print("Program starts in %d seconds" % (5 - i))
sleep(1)
# Get an active window.
screen = Gdk.Screen.get_default()
window = Gdk.Screen.get_active_window(screen)
def loop():
# Close the window in the middle of this callback.
print(window.get_geometry()) # Crash
return True
GLib.timeout_add(100, loop)
Gtk.main()
如果我在开始执行之前打开一个窗口loop()
,然后突然关闭中间的窗口loop()
,程序会因 X11 错误而崩溃。
Gdk-ERROR **: 00:13:54.693: The program 'test.py' received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadDrawable (invalid Pixmap or Window parameter)'.
(Details: serial 175 error_code 9 request_code 14 (core protocol) minor_code 0)
(Note to programmers: normally, X errors are reported asynchronously;
that is, you will receive the error a while after causing it.
To debug your program, run it with the GDK_SYNCHRONIZE environment
variable to change this behavior. You can then get a meaningful
backtrace from your debugger if you break on the gdk_x_error() function.)
很明显,它崩溃是因为这个 GDKWindow 后面的底层 X11 窗口之前已经消失了get_geometry()
。但是如何确保 GDKWindow 仍然有效?我尝试使用is_destroyed()
,process_all_updates()
和flush()
,但没有任何效果。
已解决:正如重复的问题所示,X 是一个异步协议,因此根本不可能确保窗口存在。相反,我们应该做的是安装一个异常处理程序,以便在错误发生后从 X 中捕获错误。在 GDK 中,异常处理可以通过gdk_x11_display_error_trap_push()
(开始忽略并记录异常)和gdk_x11_display_error_trap_pop()
(如果有则返回错误代码)来实现。
正确的程序如下所示。
from time import sleep
from gi.repository import GLib, Gtk, Gdk, GdkX11
# (Open and select a window before the program starts.)
print("Open your window and focus on it.")
for i in range(5):
print("Program starts in %d seconds" % (5 - i))
sleep(1)
# Get an active window.
screen = Gdk.Screen.get_default()
window = Gdk.Screen.get_active_window(screen)
def loop():
# Close the window in the middle of this callback.
# ignore and catch all errors at this point.
display = GdkX11.X11Display.get_default()
GdkX11.X11Display.error_trap_push(display)
# do something that may throw an X error
print(window.get_geometry())
# stop ignoring errors, return the error code if any
error = GdkX11.X11Display.error_trap_pop(display)
if (error == 0):
print("previous operation succeed.")
else:
print("previous operation failed, error %d." % error)
# do error recovery here
return True
GLib.timeout_add(100, loop)
Gtk.main()
输出:
(x=0, y=0, width=952, height=545)
previous operation succeed.
(x=0, y=0, width=952, height=545)
previous operation succeed.
(x=-1013446544, y=22086, width=-1013446512, height=22086)
previous operation failed, error 9.
(x=-1013446544, y=22086, width=-1013446512, height=22086)
previous operation failed, error 9.
解决方案
推荐阅读
- node.js - HTTPS AWS Elastic Beanstalk
- c++ - 如果“所有者”,C ++类析构函数删除成员?
- windows - Powershell ICACLS 更改文件的权限
- csv - WSO2:将 CSV 消息转换为 json wso2 esb 。序言中出现意外字符'"'(代码34)失败;预期'<'
- sapui5 - Fiori 中语义对象的用途
- csrf - 如何保护 Auth0 认证的 REST 服务免受 XSRF 和会话劫持?
- javascript - 我正在接受挑战
- python - FastICA 的问题,修改一个独立的源会改变所有的输出
- c++ - 在 C++11 函数中使用尾随返回类型的优势
- python - 如何将具有自定义用户设置的 Django 中间件添加为 Python 包?