我陷入困境,不知道在哪里看得更远。
我有一个Java应用程序,其function之一是抢到一些特定的窗口(即第三方应用程序窗口),并将它们托pipe在自己的内部(有一些额外的框架等)。整个事情效果很好,除了当我的Java应用程序死亡(或崩溃)。 发生这种情况时,托pipe的第三方窗口会被破坏,大部分时间都是第三方应用程序崩溃。
此function旨在在Linux下工作。
重build的方式有些复杂:
我写了一个虚拟的C程序,它使用大部分库代码(不包含JNI位)来使用xclock作为托pipetesting应用程序来debugging此问题。 我可以重现完全相同的行为:当杀死虚拟程序时, Xclock窗口消失, xclock崩溃后不久。
然后我修改共享库例程以使用XAddToSaveSet函数。 这对我的示例程序有效: Xclock窗口被正确地恢复并重新设置到ROOT窗口。 现在,用Java应用程序做同样的事情是行不通的:托pipe窗口不会重新安装到ROOT窗口。
我已经使用gdb , xev和xmon监视了正在发生的事情 。 正确调用XAddToChangeSet ,我可以看到ChangeSet请求通过xmon (和窗口ID是正确的),但是当Java应用程序崩溃事件DestroyWindow发送到托pipe窗口,当我期待看到一个RemapWindow事件(就像使用示例C程序时一样)。
有没有人从Java世界玩过这种东西?
Java应用程序是相当大的:multithreading和使用OpenGL(也许很重要)。 在RHEL4和RHEL6上的行为是相同的。 没有窗口pipe理器运行,只是一个裸X服务器(XOrg X11 1.10.2)。
任何其他方式来debugging呢? 我们可以以某种方式观察存盘吗? XServer是否应该向ChangeSet请求发送回复?
我的下一步是编写一个示例Java应用程序,并使用主应用程序正在执行的相同方式使用JNI接口,但希望有一些明显的我错过了。
谢谢!
[编辑]
我终于用一个虚拟的Java应用程序进行了testing:一个JPanel和XClock重新载入面板。 当Java进程被终止时,XClock窗口被销毁。
下面的示例C代码(使用Xlib)的XMON日志的摘录:
VisibilityNotify event, serial 13, synthetic NO, window 0x20000a, state VisibilityPartiallyObscured UnmapNotify event, serial 13, synthetic NO, window 0x20000a, event 0x20000a, window 0x20000a, from_configure NO ReparentNotify event, serial 13, synthetic NO, window 0x20000a, event 0x20000a, window 0x20000a, parent 0x600001, (0,0), override NO MapNotify event, serial 13, synthetic NO, window 0x20000a, event 0x20000a, window 0x20000a, override NO VisibilityNotify event, serial 13, synthetic NO, window 0x20000a, state VisibilityPartiallyObscured . . . UnmapNotify event, serial 13, synthetic NO, window 0x20000a, event 0x20000a, window 0x20000a, from_configure NO ReparentNotify event, serial 13, synthetic NO, window 0x20000a, event 0x20000a, window 0x20000a, parent 0x282, (11,11), override NO MapNotify event, serial 13, synthetic NO, window 0x20000a, event 0x20000a, window 0x20000a, override NO VisibilityNotify event, serial 13, synthetic NO, window 0x20000a, state VisibilityUnobscured
使用Java代码,会出现相同的初始化顺序,但是在处理该进程时不会发生ReparentNotifyEvent 。
遵循Andrey的build议,我实现了Xfixes扩展 XFixesChangeSaveSet 。 版本1似乎完全解决了这个问题(或足够接近):
- 保存设置处理更改。 在存在嵌套的情况下,核心存储集处理会中断。 这个扩展使embedded应用程序更可靠
不幸的是,没有改变。
所以我想我会放弃这一个,find其他的解决方法。
[编辑2]
我不得不再次重新讨论这个问题,通过正确的重新编码XFixes API,它一切正常!
所以最后,代码:
XReparentWindow(display, childWindowId, newParentWindowId, 0, 0); XFixesChangeSaveSet(display, childWindowId, SetModeInsert, SaveSetRoot, SaveSertMap);
做的伎俩。
“事件DestroyWindow发送到托管窗口”听起来像是java运行时间做清理(而不是保存设置)。 从x11协议的 “连接关闭”部分10:
When a client's resources are destroyed, for each window in the client's save-set, if the window is an inferior of a window created by the client, the save-set window is reparented to the closest ancestor such that the save-set window is not an inferior of a window created by the client. If the save-set window is unmapped, a MapWindow request is performed on it (even if it was not an inferior of a window created by the client). The reparenting leaves unchanged the absolute coordinates (with respect to the root window) of the upper-left outer corner of the save-set window. After save-set processing, all windows created by the client are destroyed. For each nonwindow resource created by the client, the appropriate Free request is performed. All colors and colormap entries allocated by the client are freed.
可以在崩溃之前和之后几秒钟发布xmon(或xtruss或xtrace)通信转储吗?
另外,对于像“重新设置这个窗口并添加到保存集”这样的简单操作,我会尝试使用像https://github.com/xderoche/J11这样的低级客户端,并避免所有这些“额外的线程+ ffi调用.so (是那个xlib?)“