XLib:Windows 管理器在调用 XSetWMProtocols 后不发送客户端消息

XLib: Windows Manager not Sending Client Message after Calling XSetWMProtocols

网上有很多关于如何使用 XLib 处理 window 关闭的例子:

还有几个。也就是说,我已经尝试在代码中实现它们,如下所示。但是,当我单击 window 角落的 X 时,没有任何事件发送到我的消息循环。这是因为 XChcekWindowEvent 忽略或不处理客户端消息吗?如果不是这种情况,我应该寻找哪些其他东西来从使用 SetWMProtocols 的 XLib 集获取消息?

m_impl->m_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
if (!XSetWMProtocols(display, window, &m_impl->m_delete_window, 1)) {
  std::cout << "Set Window Protocols Failed" << std::endl;
}

...

while (!terminate) {
  while (::XCheckWindowEvent(display, window, events::mask, &x_event)) {
    if (x_event.type == ClientMessage) {
      std::cout << "Client Message" << std::endl;   
      if ((Atom)x_event.xclient.data.l[0] == m_impl->m_delete_window) {
        terminate = true;
      }
    }
  }
}

XCheckWindowEvent() 不会returnClientMessage。它 returns none 个不可屏蔽的。解决方法:

while (XPending(display))
{
    XNextEvent(display, &event);

但是 window 可以创建额外的工作来过滤事件。 BR 佩卡

如果你想阻止使用XNextEvent(实时事件循环中没有应用),你可以在XCheckTypedWindowEvent的基础上使用下面的代码:

// Globals

Atom wm_protocols;
Atom wm_delete_window;

// Functions

void PreventClose(Display* disp, Window& win)
{
  wm_protocols = XInternAtom(disp, "WM_PROTOCOLS", false);
  wm_delete_window = XInternAtom(disp, "WM_DELETE_WINDOW", false);
  XSetWMProtocols(disp, win, &wm_delete_window, 1);
}

bool IsClosed(Display* disp, Window& win)
{
  XEvent e;
  if (XCheckTypedWindowEvent(disp, win, ClientMessage, &e))
    if (e.xclient.message_type == wm_protocols &&
        e.xclient.data.l[0]    == wm_delete_window_)
      return true;
  return false;
}

// Usage

int main()
{
   ...
   PreventClose(disp, win);
   do {
     if (IsClosed(disp, win))
       // break, some actions, etc...
     ...
   } while(true);
   return 0;
}

有关详细信息,请参阅 man 3 XCheckTypedWindowEvent