XLib - 如何正确取消增量数据传输的过程?

问题描述

我已阅读 this 并在 Internet 上的许多其他地方进行了查找,但我找不到问题的答案。在 C++ 程序中,我有一个Clipboard。此类正在监视 X11 选择事件,并在其更改时将选择内容提取到字符串成员中。对于大型选择,X11 使用“INCR 传输”机制。这个过程在上面的链接中有描述。获取大选择的内容时,我想检查选择大小是否超过某个限制(比如 20 兆字节),如果是,我不希望获取此选择以避免我的程序内存消耗不足.这大致是我目前的做法:

void Clipboard::fetchLargeSelectionContent()
{
    /* We have received a property of type 'INCR' and are Now going to start
       the read process 
       Variables ending with '_' are class' private members */
    Atom clipboard = XInternAtom(display_,"CLIPBOARD",false);
    Atom target = XInternAtom(display_,"UTF8_STRING",false);
    unsigned long nItemsToRead = 0;
    Atom typeReturned = None;
    int formatReturned = 0;
    unsigned long nItemsReturned = 0;
    unsigned long nBytesRemaining = 0;
    unsigned char* dataReturned = nullptr;
    // We do not want selection to exceed 20 megabytes
    std::string::size_type sizeLimit = 20 * 1024 * 1024;
    bool maxSizeExceeded = false;
    // Listen for property events on the requestor's(us) window
    XSelectInput(display_,window_,PropertyChangeMask);
    /* The xlib::getCurrentTime() function is defined in a separate header file
       and returns the current X server time */
    Time propertyReadTime = xlib::getCurrentTime();
    /* Notify the selection owner that we are ready to receive the data
       by deleting the property of type 'INCR' */
    XDeleteProperty(display_,property_);
    while (true)
    {
        XEvent event{};
        XNextEvent(display_,&event);
        if (event.type == PropertyNotify &&
                event.xproperty.state == PropertyNewValue &&
                event.xproperty.display == display_ &&
                event.xproperty.window == window_ &&
                event.xproperty.time >= propertyReadTime)
        {
            // Read zero bytes from the property just to get the size of its content
            XGetwindowProperty(
                    display_,property_,false,target,&typeReturned,&formatReturned,&nItemsReturned,&nBytesRemaining,&dataReturned);
            XFree(dataReturned);
            dataReturned = nullptr;
            if (nBytesRemaining == 0)
            {
                // Transfer completed
                XDeleteProperty(display_,property_);
                break;
            }
            nItemsToRead = nBytesRemaining;
            propertyReadTime = xlib::getCurrentTime();
            // Read the content and delete the property requesting a new data chunk
            XGetwindowProperty(
                    display_,nItemsToRead,true,&dataReturned);
            if (!maxSizeExceeded)
            {
                content_ += std::string(
                        reinterpret_cast<const char*>(dataReturned),nItemsReturned);
                maxSizeExceeded = content_.size() > sizeLimit;
            }
            XFree(dataReturned);
            dataReturned = nullptr;
        }
    }
    if (maxSizeExceeded)
    {
        content_.clear();
        std::string().swap(content_);
    }
    XSelectInput(display_,NoEventMask);
}

这种方法有效,但它有一个明显的缺点——即使在超过 sizeLimit 后仍会收到数据,只是不会写入 content_。但是为什么我要接收我不打算存储和使用的数据?我需要以某种方式通知选择所有者我不再对接收新数据块感兴趣,并且它应该中止 INCR 传输过程。但我还没有找到一种方法来做到这一点。我试图简单地用 while (true) 替换 while (!maxSizeExceeded) 以在超过 sizeLimit 后立即中断循环。但似乎选择所有者仍在等待我的程序读取它发送的数据,因为我可以看到系统内存使用量显着增长,每次复制 500MB 文本数据。如果使用我示例中的方法,则不会发生这种情况(读取整个数据,如果数据太大则忽略它)。

那么,问题就在标题中——如何优雅地(正确地)中止增量数据传输的过程,有没有办法做到这一点?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)