在 X11 里面有和 Win32 类似的窗口之间的关系机制,如 Owner-Owned 关系,以及 Parent-Child 关系。本文将告诉大家如何进行设置以及其行为
本文将大量使用到 new bing 提供的回答内容,感谢 new bing 人工智能提供的内容
Owner-Owned 关系
- 在这种关系中,一个窗口可以被另一个窗口拥有(owner)。
- 被拥有的窗口永远显示在拥有它的那个窗口的前面。
- 当所有者窗口最小化时,它所拥有的窗口也会被隐藏。
- 当所有者窗口被销毁时,它所拥有的窗口也会被销毁。
- 当子窗口最小化时,不会影响到所有者窗口
- 子窗口可以超过所有者窗口的范围
被拥有的窗口 = 子窗口
所有者窗口 = “在拥有它的那个窗口”
即与 WPF 的 ChildWindow.Owner = MainWindow 的效果类似。以上的 ChildWindow 为子窗口,而 MainWindow 为 所有者窗口
核心 C# 代码如下
通过关系的描述可以了解到,使用上面代码即可设置 a 窗口一定在 b 窗口上方。此方法在 XMapWindow 之前和之后调用都生效
以上代码放在 github 和 gitee 上,可以使用如下命令行拉取代码
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码
获取代码之后,进入 GececurbaiduhaldiFokeejukolu 文件夹,即可获取到源代码
建立三个窗口关系
使用 XSetTransientForHint 时不能让一个窗口同时在两个窗口的上方,比如说有 win1 和 win2 和 win3 三个窗口,通过以下代码调用两次 XSetTransientForHint 方法,是不能让 win1 保持在 win2 和 win3 窗口的上方的
以上代码的效果只是让 win1 保持在 win3 的上方,而断开 win1 和 win2 的关系。此时可以看到 win2 可以放在 win1 的上方,即 XSetTransientForHint 是覆盖设置的用途,而不是追加的功能
以上测试代码放在 github 和 gitee 上
但如果是层叠关系则是可以的,即是 win1 在 win2 之上,而 win2 在 win3 之上,这是完全没有问题的,如以下代码
以上代码的效果就是 win3 在最底层,且 win2 保持在 win3 之上,而 win1 则在最上层
以上测试代码放在 github 和 gitee 上
窗口关系断开
额外说明的是 XSetTransientForHint 关系的保持也会在 XUnmapWindow 之后断开
如下面代码,设置 win1 和 win2 关系,让 win1 在 win2 的上方
此时如果先 XUnmapWindow 再 XMapWindow 显示 win1 窗口,那么 win1 和 win2 的关系依然保持,即依然 win1 在 win2 的上方
此时如果 XUnmapWindow 再 XMapWindow 显示 win2 窗口,那么 win1 和 win2 的关系将被断开。即此时 win1 和 win2 谁在上方取决于谁被激活,不再保持 win1 一定在 win2 的上方
以上测试代码放在 github 和 gitee 上
继续测试。如果此时再次调用 XSetTransientForHint(display, win1, win2)
代码尝试建立窗口之间的关系,那将没有效果。无法让 win1 在 win2 的上方
以上测试代码放在 github 和 gitee 上
想要在 XUnmapWindow 之后再让 XSetTransientForHint 生效,需要在 XSetTransientForHint 之前先调用 XDeleteProperty 删除记录,大概代码如下
以上测试代码放在 github 和 gitee 上
以上方式不够稳健,最稳妥方式是对 win1 进行 XUnmapWindow 和 XMapWindow 之后再 XSetTransientForHint 才是稳妥的
Parent-Child 关系
- 在这种关系中,一个窗口是另一个窗口的父窗口。
- 子窗口只能显示在父窗口的客户区内。
- 当父窗口被隐藏时,它的所有子窗口也会被隐藏。
- 当父窗口被销毁时,它所拥有的子窗口也会被销毁。
核心 C# 代码如下
需要记住在 XMapWindow 之前调用 XReparentWindow 方法,否则关系设置无效
以上代码放在 github 和 gitee 上,可以使用如下命令行拉取代码
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码
获取代码之后,进入 DikalehebeekaJaqunicobo 文件夹,即可获取到源代码
建立 Parent-Child 关系之后,如果子窗口没有调用 XSelectInput 方法时,那所有在子窗口上的消息都能被所有者窗口收到,如果调用了 XSelectInput 则子窗口收到子窗口的消息,即所有者窗口被子窗口遮挡的部分将不能收到消息,被子窗口遮挡的部分的触摸或鼠标消息会被子窗口接收
简单的测试代码逻辑如下
配置了以上代码,运行项目,可以看到鼠标在子窗口上时,只能收到子窗口的消息,如下图
以上代码有所忽略,全部的代码放在 github 和 gitee 上,可以使用如下命令行拉取代码
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码
获取代码之后,进入 DikalehebeekaJaqunicobo 文件夹,即可获取到源代码
设置 Parent-Child 关系之后,将限制子窗口只能在主窗口的客户区范围内,即子窗口不能超过主窗口范围,如下图所示
以上代码是在 XReparentWindow 方法里面设置了子窗口的坐标,让子窗口超过主窗口的范围,代码如下
以上代码放在 github 和 gitee 上,可以使用如下命令行拉取代码
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码
获取代码之后,进入 DikalehebeekaJaqunicobo 文件夹,即可获取到源代码
以下是 new bing 给出的 XReparentWindow 函数的更多信息
XReparentWindow
函数的作用是将一个窗口重新设置其父窗口。具体来说,如果指定的窗口已经被映射到屏幕上,XReparentWindow
会自动执行 UnmapWindow
请求,将其从当前层次结构中移除,并将其插入到指定父窗口的子级中。这个窗口会在兄弟窗口中的堆叠顺序中置于顶部。¹²
如果原始窗口已经被映射,XReparentWindow
还会导致 X 服务器生成一个 ReparentNotify
事件。在此事件中,override_redirect
成员被设置为窗口的相应属性。通常情况下,窗口管理器客户端应该忽略此窗口,如果此成员设置为 True
。最后,如果原始窗口已经被映射,X 服务器会自动对其执行 MapWindow
请求。对于原先被遮挡的窗口,X 服务器会执行正常的曝光处理。但是,由于最终的 MapWindow
请求会立即遮挡初始 UnmapWindow
请求的某些区域,因此 X 服务器可能不会为这些区域生成 Expose
事件。¹
以下情况会导致 BadMatch
错误:
- 新的父窗口不在与旧的父窗口相同的屏幕上。
- 新的父窗口是指定窗口本身或指定窗口的下级。
- 新的父窗口是
InputOnly
类型,而窗口不是。
- 指定窗口具有
ParentRelative
背景,而新的父窗口与指定窗口的深度不同。
总之,XReparentWindow
允许您在 X 窗口系统中重新组织窗口的层次结构。
使用 XReparentWindow 设置的窗口关系时,子窗口将会挡住主窗口的渲染部分,即在子窗口范围内将看不到主窗口的绘制内容
其测试代码如下,先在主窗口和子窗口绘制内容
接着使用 XMoveWindow 设置子窗口坐标,此时可见子窗口所在地方将不可见主窗口绘制的内容
全部的测试代码如下
运行代码之后的效果如下图
如上图,应用是透明窗口,可以看到背后的图片应用显示的内容。上述图片是使用 WPF 基础绘图 创建和加工图片 绘制的图片。可以看到无论是主窗口还是子窗口都能透过去。但是子窗口将会遮挡主窗口的绘制,即让子窗口直接显示窗口之后的部分内容,但不会与主窗口合成,即主窗口被子窗口挡住的部分就没有进行渲染
以上代码放在 github 和 gitee 上,可以使用如下命令行拉取代码
先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码
获取代码之后,进入 DikalehebeekaJaqunicobo 文件夹,即可获取到源代码
更多 X11 相关,请参阅 博客导航
原文链接: http://blog.lindexi.com/post/dotnet-%E8%AE%BE%E7%BD%AE-X11-%E5%BB%BA%E7%AB%8B%E7%AA%97%E5%8F%A3%E4%B9%8B%E9%97%B4%E7%9A%84%E7%88%B6%E5%AD%90%E5%85%B3%E7%B3%BB
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系。