xcb 正确 window 大小

xcb correct window size

我有一个关于 xcb Window 尺寸的问题 我使用 xcb_create_window 函数

创建了一个 window
    xcb_create_window(mScreen->connection(),
                  XCB_COPY_FROM_PARENT,
                  mWindow,
                  mScreen->screen()->root,
                  x, // left corner of the window client area
                  y, // upper corner of the window client area
                  width, // width of the client area
                  height, // height of the client area
                  0,
                  XCB_WINDOW_CLASS_INPUT_OUTPUT,
                  mScreen->screen()->root_visual,
                  value_mask,
                  value_list);
    auto reply = XCB_REPLY(xcb_intern_atom, mScreen->connection(), true, strlen("WM_PROTOCOLS"), "WM_PROTOCOLS");
    auto atomDelete = XCB_REPLY(xcb_intern_atom, mScreen->connection(), false, strlen("WM_DELETE_WINDOW"), "WM_DELETE_WINDOW");

    xcb_change_property(mScreen->connection(), XCB_PROP_MODE_REPLACE, mWindow, reply->atom, 4, 32, 1, &atomDelete->atom);
    xcb_change_property(mScreen->connection(), XCB_PROP_MODE_REPLACE, mWindow, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, strlen(windowName), windowName);
    xcb_flush(mScreen->connection());

在 Win32 上 API 我可以通过使用 AdjustWindowRect 函数来调整 window 矩形,该函数主要是添加边框和标题大小以确保客户端 window 确实有预期大小。

我的问题是如何使用 xcb 实现此目的?有什么方法可以计算确保客户端 window das 具有预期大小所需的附加大小?

Extended Window Manager Hints

_NET_REQUEST_FRAME_EXTENTS(其他根 Window 消息)

Rationale: A client cannot calculate the dimensions of its window's frame before the window is mapped, but some toolkits need this information. Asking the window manager for an estimate of the extents is a workable solution. The estimate may depend on the current theme, font sizes or other window properties. The client can track changes to the frame's dimensions by listening for _NET_FRAME_EXTENTS PropertyNotify events.

_NET_FRAME_EXTENTS(应用程序 Window 属性)

The Window Manager MUST set _NET_FRAME_EXTENTS to the extents of the window's frame. left, right, top and bottom are widths of the respective borders added by the Window Manager.

示例可在此处找到:

以下代码获取 window 的边距 遵循 Erdal Küçük 的建议:

  • 创建window

  • 配置内容(如标题或关闭按钮)

  • 等待属性消息

  • 以防_NET_FRAME_EXTENTS读取数据

      uint32_t value_mask, value_list[32]{};
      auto windowHandle = xcb_generate_id(xcb_connection());
      value_mask = XCB_CW_EVENT_MASK;
      value_list[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
    
      xcb_create_window(screen->connection(),
                        XCB_COPY_FROM_PARENT,
                        windowHandle,
                        screen->root,
                        100,
                        100,
                        100,
                        100,
                        0,
                        XCB_WINDOW_CLASS_INPUT_OUTPUT,
                        screen->root_visual,
                        value_mask,
                        value_list);
    
      auto protocols = XCB_REPLY(xcb_intern_atom, screen->connection(), true, strlen("WM_PROTOCOLS"), "WM_PROTOCOLS");
      auto atomDelete = XCB_REPLY(xcb_intern_atom, screen->connection(), false, strlen("WM_DELETE_WINDOW"), "WM_DELETE_WINDOW");
      auto atomExtents = XCB_REPLY(xcb_intern_atom, screen->connection(), false, strlen("_NET_FRAME_EXTENTS"), "_NET_FRAME_EXTENTS");
    
      xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, windowHandle, protocols->atom, XCB_ATOM_ATOM, 32, 1, &atomDelete->atom);
      xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, windowHandle, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, strlen(""), "");
      xcb_map_window(xcb_connection(), windowHandle);
      xcb_flush(xcb_connection());
      xcb_generic_event_t* event;
    
      for (;;) {
          while ((event = xcb_poll_for_event(screen->connection()))) {
              switch (event->response_type & 0x7f) {
                  case XCB_PROPERTY_NOTIFY: {
                      auto propertyNotify = (const xcb_property_notify_event_t*)event;
    
                      if (propertyNotify->atom == atomExtents->atom) {
                          free(event);
                          goto end;
                      }
                      break;
                  }
                  default:
                      break;
              }
              free(event);
          }
      }
      end:
      auto extends = XCB_REPLY(xcb_get_property, xcb_connection(), false, windowHandle, atomExtents->atom, XCB_ATOM_CARDINAL, 0, 4);
      if (extends && extends->type == XCB_ATOM_CARDINAL && extends->format == 32 && extends->value_len == 4) {
          uint32_t* data = std::pointer_cast<uint32_t*>(xcb_get_property_value(extends.get()));
          windowMargins.l = -data[0];
          windowMargins.r = data[1];
          windowMargins.t = -data[2];
          windowMargins.b = data[3];
      }
    
      xcb_destroy_window(xcb_connection(), windowHandle);