【问题标题】:Old xlib programs hang the Linux GUI on window resize. Why?旧的 xlib 程序在调整窗口大小时会挂起 Linux GUI。为什么?
【发布时间】:2023-04-07 17:13:01
【问题描述】:

我注意到,对于较旧的 X 程序,当用户开始通过拖动窗口边缘来调整窗口大小时,操作系统的整个 GUI 会冻结。

我正在使用 glxgears 进行测试 - 齿轮停止旋转。所有其他程序的内容更新也是如此 - 例如任务管理器、终端窗口等。

停止移动鼠标后,所有活动重新开始。

调整新程序窗口的大小(我的意思是使用 GTK 或 Qt)不会冻结任何东西。

同时,旧程序的 GUI 比新程序的响应速度更快。只有拖动调整大小是问题。

较旧的程序都使用标准的文档化方式来处理消息队列。类似于以下内容(当然更复杂):

while (1) {
      XNextEvent(d, &e);
      if (e.type == Expose) {
         XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10);
         XDrawString(d, w, DefaultGC(d, s), 10, 50, msg, strlen(msg));
      }
}

我试图通过在主窗口创建时设置XSetWindowAttributes.event_mask = 0 来消除整个消息处理。事件完全停止流动,但在调整空窗口大小时,所有 GUI 仍然冻结。

因此,问题不(仅)在客户端。虽然,它可能是客户端和服务器交互的方式。例如,可能是因为客户端没有做某事。

那么,较新的工具包有何不同之处?在旧程序中进行哪些更改以避免此类冻结。

【问题讨论】:

  • 不确定,但我猜至少有一些差异是由于在许多当前基于X11 的应用程序中使用libxcb 而不是XLib。它的级别更低,更异步(或“不那么同步”——任你选择)。
  • @G.M.是的,但是据我所知,最新版本的 Xlib 实际上也是基于 xcb 的。所以,应该没有区别。或者好吧,Xlib 实现中存在一些错误......但是,即使没有调用任何 Xlib 函数,外部操作(来自窗口管理器)也会导致整个系统冻结......
  • @G.M.好吧,我尝试编译仅使用 xcb(来自 en.wikipedia/xcb)的简单示例,它以相同的方式挂起 GUI... :(

标签: c++ c linux gtk xlib


【解决方案1】:

嗯,经过一番研究,我找到了答案。

问题在于旧程序不使用_NEW_WM_SYNC_REQUEST protocol 来使它们重绘窗口内容的能力与来自窗口管理器的调整大小事件的速率同步。

因此,窗口管理器调整窗口大小的速度太快,应用程序无法快速绘制。这样,窗口管理器可以有效地加载 X 服务器,并为其他正在运行的应用程序提供 DoS 挂起。

当然,在这种情况下,调整大小事件的频率取决于窗口管理器,但其中大多数只是在每次鼠标移动时调整窗口大小。

_NET_WM_SYNC_REQUEST 协议旨在在应用程序完成其窗口的绘制时向窗口管理器提供信息,并在处理之前的调整大小之前阻止它调整窗口大小。

实现非常简单。

首先,应用程序必须在窗口的 WM_PROTOCOLS 属性中包含 _NET_WM_SYNC_REQUEST。

此外,应用程序应提供一个(可能是两个)同步计数器(参见SYNC X 扩展或xcb-sync librarylibX variant

那么协议如下所示:

  1. 在调整窗口大小之前,WM 向应用程序 ClientMessage 发送数据 [0] 设置为 _NEW_WM_SYNC_REQUEST 字符串的 Atom。在这个事件的 data[2] 和 data[3] 中有一个 64 位的数字。应用程序必须将此号码存储在某处。

  2. 在处理完以下 ConfigureNotify 和 Expose 事件并完全重绘窗口表面后,它必须将同步计数器设置为这个 64 位值。

  3. 窗口管理器检查计数器的值,在看到它的数字后,就知道再次调整窗口大小是安全的。

当然,有一些超时机制,如果程序响应太慢或根本没有响应,窗口管理器会切换到回退模式并开始以旧方式调整窗口大小。

此协议还有另一个变体,带有两个同步计数器,但恕我直言,它旨在解决另一个程序。随着窗口大小的调整,协议的第一个版本运行良好。

【讨论】:

    猜你喜欢
    • 2019-10-20
    • 2016-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 2019-05-15
    相关资源
    最近更新 更多