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

时间:2014-09-17 12:23:36

标签: java linux x11 xlib

我陷入困境,不知道该往哪里看。

我有一个Java应用程序,它的一个功能是获取一些特定的窗口(即第三方应用程序窗口)并将它们托管在自身内(带有一些额外的框架等等) 整个过程非常有效,除非我的Java应用程序被杀死(或崩溃)。发生这种情况时,托管的第三方窗口会被破坏,大部分时间都会崩溃第三方应用程序。

此功能旨在在Linux下运行。

重新完成的方式有点复杂:

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

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

然后我修改共享库例程以使用 XAddToSaveSet 功能。 这对我的示例程序很有用: Xclock 窗口可以正确恢复并重新定位到ROOT窗口。 现在使用Java应用程序做同样的事情是行不通的:托管窗口没有被重新定位到ROOT窗口。

我已经使用 gdb xev 以及 xmon 监控了正在发生的事情。正确调用了 XAddToChangeSet ,我可以通过 xmon 看到 ChangeSet 请求(并且窗口ID是正确的) ),但是当Java应用程序崩溃时,事件 DestroyWindow 被发送到托管窗口,当我希望看到 RemapWindow 事件时(比如使用示例C程序时)

有没有人在Java世界中玩这种东西?

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

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

我的下一步是编写一个示例Java应用程序,并以与主应用程序相同的方式使用JNI接口,但希望有一些我错过的东西。

谢谢!

[编辑]

我最终使用虚拟Java应用程序进行了测试:一个JPanel并将XClock重新显示在面板上。 当Java进程被杀死时,XClock窗口就会被破坏。

下面带有示例C代码的XMON日志摘录(使用Xlib):

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似乎正好解决了这个问题(或足够接近):

  
      
  • 保存设置处理更改。核心存储集处理中断   嵌套的存在。此扩展程序使嵌入应用程序   更可靠
  •   

不幸的是,没有变化。

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

[编辑2]

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

最后,代码:

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

诀窍。

1 个答案:

答案 0 :(得分:2)

"将事件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?)"