java - Xlib:使用 XAddToChangeSet 向保存集添加窗口在 Java/JNI 中不起作用

标签 java linux x11 xlib

我卡住了,不知道该往哪里看。

我有一个 Java 应用程序,它的功能之一是抓取一些特定的窗口(即第三方应用程序窗口)并将它们托管在自身内部(带有一些额外的框架等...) 整个过程都很好,除非我的 Java 应用程序被杀死(或崩溃)。发生这种情况时,托管的第三方窗口会被破坏,大多数情况下会导致第三方应用程序完全崩溃。

此功能专为在 Linux 下工作而设计。

重新设置父级的方式有点复杂:

  • 一个专用的 Java 线程被创建并调用一个 C 共享库(一个 .so 库)。
  • 此共享库扫描所有当前窗口并识别需要托管的窗口
  • 当检测到这样的窗口时,使用 XReparentWindow
  • 将其重新定位到主 Java 应用程序窗口
  • 共享库进入无限循环(由退出标志控制)并等待 XEvent(使用 XNextEvent)以防需要托管的窗口被获取显示。

我编写了一个虚拟 C 程序,它使用大部分库代码(没有 JNI 位)来使用 xclock 作为我的托管测试应用程序来调试此问题。 我可以重现完全相同的行为:当终止虚拟程序时,Xclock 窗口消失并且在 xclock 崩溃后不久。

然后我修改共享库例程以使用 XAddToSaveSet 函数。 这对我的示例程序很有用:Xclock 窗口得到正确恢复并重新设置为 ROOT 窗口的父级。 现在对 Java 应用程序做同样的事情不起作用:托管窗口没有重新定位到 ROOT 窗口。

我已经使用 gdbxevxmon 监控了正在发生的事情。 XAddToChangeSet 被正确调用,我可以看到 ChangeSet 请求通过 xmon(并且窗口 ID 正确),但是当 Java 应用程序崩溃时,事件 DestroyWindow 被发送到托管窗口,而我期望看到一个 RemapWindow 事件(就像使用示例 C 程序时一样) .

有人玩过 Java 世界的这种东西吗?

Java 应用程序非常大:多线程并使用 OpenGL(可能很重要)。该行为在 RHEL4 和 RHEL6 上是相同的。 没有运行窗口管理器,只有一个裸 X 服务器 (XOrg X11 1.10.2)。

还有其他调试方法吗? 我们能否以某种方式观察保存集? XServer 是否应该对 ChangeSet 请求发送回复?

我的下一步是编写一个示例 Java 应用程序,并像主应用程序一样使用 JNI 接口(interface),但希望我遗漏了一些明显的东西。

谢谢!

[编辑]

我最终使用虚拟 Java 应用程序进行了测试:一个 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 的建议,我实现了 Xfixes extension XFixesChangeSaveSet。 版本 1 似乎完全解决了这个问题(或足够接近):

  • Save Set processing changes. Core save set processing breaks in the presence of nesting. This extension makes embedding applications more reliable

很遗憾,没有任何变化。

所以我想我会放弃那个并找到其他解决方法。

[编辑 2]

我不得不再次重新审视这个问题,通过正确地重新编码 XFixes API,一切正常!

所以最后,代码:

XReparentWindow(display, childWindowId, newParentWindowId, 0, 0);
XFixesChangeSaveSet(display, childWindowId, SetModeInsert, SaveSetRoot, SaveSertMap);

成功了。

最佳答案

“事件 DestroyWindow 被发送到托管窗口”听起来像是 Java 运行时在进行清理(并且不考虑保存集)。来自 x11 protocol 的“连接关闭”第 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 吗?)”

关于java - Xlib:使用 XAddToChangeSet 向保存集添加窗口在 Java/JNI 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25890486/

相关文章:

c++ - X11 Unicode KeyEvent 问题

c - 如何使用 X11 复制到剪贴板?

c - 如何为 Linux 编写 Hello world 驱动程序

linux - BadAlloc 并在 wxWidgets 程序中崩溃。如何找到错误?

java - 如何模拟jsp :param in SpringMVC

java - "Link doesn' t work”添加基本的 Spring Security 支持后

Java在简单方程式中重复小数

java - 更新 Spring Mongo 的服务器时间

linux - 如何在 CentOS 5 中构建 linux 可执行文件并在 RedHat 9 上运行它?

linux - 用户空间中 x86-64 Linux 上 CS 和 SS 寄存器的含义?