5

我有一个 1990 年代早期编写的遗留 Motif 应用程序(我无法在 QT 中重写 UI,甚至无法在不经过耗时的安全评估的情况下广泛修改应用程序)。这个应用程序曾经在 AIX 上运行,它在密集使用的情况下连续运行了数周,并且非常稳定。我们现在已经将它移植到 Linux 上。在长时间的持续 Beta 测试期间,该应用程序大约每周崩溃一次,并显示以下消息。

失败请求的错误:BadWindow(无效的窗口参数)
失败请求的主要操作码:4(X_DestroyWindow)

从那以后,我了解到可以使用自定义 X11 错误处理程序(默认的 X11 错误处理程序仅打印错误消息并退出)忽略这些错误,如下所述:

http://motifdeveloper.com/tips/tip29.html

我已经实现了一个自定义 X11 错误处理程序,它忽略了该文章中描述的 BadWindow 错误。所以我的问题是:比我更了解 X11 开发和 X 服务器内部工作原理的人能否告诉我 BadWindow 错误是否真的可以像那样被忽略?

PS 我将尝试通过在同步模式下运行我们的应用程序来进一步调试它,但这很慢,因为我无法按需重现此错误。任何有关调试 BadWindow 错误的提示也将不胜感激。

4

3 回答 3

5

如果您的程序由单个进程(与 X 显示器的单个连接)组成,那么此错误几乎总是反映程序中的错误。

要知道的秘密是如何调试它。因为 Xlib 是异步的,所以XDestroyWindow()会触发后忘记,窗口上的一些后销毁操作也可能触发后忘记,并且您在将来的某个时间(在其他一些不相关的 X 调用期间)会收到错误。这意味着来自 X 错误的堆栈跟踪是没有意义的,并且很难调试。

要解决此问题,请调用XSynchronize(dpy, True)以强制所有调用同步。这将使应用程序变慢,因此不要将其留在生产中。http://www.x.org/releases/X11R7.6/doc/man/man3/XSynchronize.3.xhtml

但是在同步模式下,如果 Xlib 调用使用了错误的窗口,它将立即失败。因此,您可以设置一个调试断点,例如在您的错误处理函数上,并获得有意义的回溯。这应该向您显示哪个 Xlib 调用导致了问题 - 并且希望它是一个小部件的双重删除,使用一个被破坏的小部件,或者什么会很清楚。

如果您的应用程序确实有多个进程或多个显示连接,例如在窗口管理器中,那么 a 可能BadWindow是不可避免的(如果您试图弄乱另一个应用程序的窗口,那么另一个应用程序的窗口可能是不可避免的竞争销毁)。在这种情况下,忽略BadWindow是正确的解决方案,尽管最佳做法是仅在那些已知会触发它的调用期间忽略它,因此您仍然可能会遇到可能是错误的错误。一个常见的习惯用法是实现一个error_trap_push()/ error_trap_pop(),它只是安装和卸载忽略错误的错误处理程序。当您触摸可能在您无法控制的情况下删除的外部窗口时,推送错误陷阱。

于 2014-01-02T21:38:13.197 回答
1

这看起来像一个按钮(或类似的 UI 元素)被多次删除。通常,按钮被实现为专用窗口,其中发出按钮图形,这样您就可以简单地将回调处理程序绑定到相关窗口中的单击事件。

该错误表示您的程序已尝试删除一个不存在的窗口 ID,而发生这种情况的最简单方法确实是它已被删除两次(或者,某些地方更改了为某个 UI 元素记录的 ID)。

此时,您不想忽略错误,您希望获得足够的日志记录以找出应用程序的问题所在。

于 2014-01-01T18:02:10.163 回答
0

在这种情况下,错误告诉您您的程序请求销毁一个不存在的窗口 id。如果您忽略它,那么您可能会泄漏您真正打算破坏的任何窗口;或者您可能只是试图两次销毁相同的窗口 id,但什么都不会改变。如果不追查为什么您的程序使用无效 id 调用 XDestroyWindow 的根本原因,很难说如果您忽略它会发生什么。

于 2014-01-02T21:24:03.703 回答