C++ 中的 X11 - 只要在 window 调整大小时设置 ResizeRedirectMask,就会发生裁剪

X11 in C++ - Cropping happens whenever ResizeRedirectMask is set when the window is resized

故事

我使用 X11/XlibLinux 系统 制作了一个显示图形的简单绘图程序。

它有一个菜单和一个绘图编辑器。

它需要知道window的大小,所以,一开始我用XGetWindowAttributes()
但是,我发现它对我来说太慢了

因为我每帧都执行函数,所以我的程序很慢。

然后,我 尝试 到 运行 函数 较少 类似每 4 帧 但这是造成 闪烁 .

我想要一个可以在每次 window 的大小更改为 运行 时生成的事件,函数仅在大小更改时发生 .

原始修复:

我发现 ResizeRequest 做我想做的事情 并输出 window 的大小作为奖励。
所以我不再需要 XGetWindowAttributes() 了。这 大大加快了程序速度。
在缩小 window.

时效果很好

新一期:

我发现当windows调整大小比原始大小时,每个对象在原始范围外 绘制得到 裁剪,如图所示。

我们可以看到 应该在 window 周围的灰色边框被裁剪掉了 全部变成黑色 。尤其是 右上角 调色板有 16 种颜色,但 4 种颜色被半裁剪了 8 种颜色没有在这里完全可见


我想做的事情:

我想知道如何通过解决以下问题之一来解决裁剪问题:

  1. 如果我必须批准调整大小 发送事件,我该怎么办?
  2. 如果我必须弄乱 缓冲区,我该怎么办?

曲目:

我的程序有一个菜单仍然使用 XGetWindowAttributes(),编辑器 (如图所示) 使用 ResizeRequest 事件,XGetWindowAttributes().
快 正如预期的那样,裁剪发生在编辑器中而不是菜单中。
但我注意到我可以 更改 window 的大小而无需裁剪 如果我在菜单中然后在编辑器中更改它,并且 它有效 !

然后我发现 只要在 XSelectInput() 函数中设置 ResizeRedirectMask,就会发生裁剪。

引用自 10.11.4 ResizeRequest 事件页面的 Xlib Programming Manual

Any attempts to change the size by other clients are then redirected.

我想,这意味着它不会影响 windows 大小(这是我用 XGetWindowAttributes() 并行测试时的结果)。那么,我必须批准调整大小,但是如何?

引自的回答。

I would clear the front buffer and await resize to complete.

我该怎么做?


示例代码:

我制作了一个简短的程序,可以在任何地方显示随机彩色方块,甚至在 window 之外。 程序运行如果你复制它。

有一个#if声明,您可以更改以查看预期(false)与实际(true)之间的差异

#include <X11/Xlib.h>
#include <cstdint>
#include <unistd.h>

#if true //Make it true to set ResizeRedirectMask and false to disable.
    #define Masks KeyPressMask|ResizeRedirectMask
#else
    #define Masks KeyPressMask
#endif

int main(){
    uint32_t RDM=0;

    uint16_t i=0;

    bool RunLoop=true;

    Display* XDisplay=XOpenDisplay(0);//Create a display
    Window XWindow=XCreateSimpleWindow(XDisplay,DefaultRootWindow(XDisplay),0,0,480,360,0,0,0);//Create a Window
    XMapWindow(XDisplay,XWindow);//Make the Window visible
    GC XGraphicCTX=XCreateGC(XDisplay,XWindow,0,0);//Create a Graphics Context

    //v Wait for a MapNotify XEvent for next commands
    XSelectInput(XDisplay,XWindow,StructureNotifyMask);
    while(1){
        XEvent e;
        XNextEvent(XDisplay,&e);
        if(e.type==MapNotify)break;
    }
    XSelectInput(XDisplay,XWindow,Masks); //Here is part of the magic error
    while(RunLoop){
        while(XPending(XDisplay)){//Get key changes
            XEvent Event;
            XNextEvent(XDisplay,&Event);
            if(Event.type==KeyPress){
                RunLoop=false;
            }
        }

        for(i=0;i<4096;i++){
            RDM=(RDM+1841)*9245;    //Not perfect but good enough
            XSetForeground(XDisplay,XGraphicCTX,RDM&0xFFFFFF);
            
            RDM=(RDM+1841)*9245;    //Not perfect but good enough
            XFillRectangle(XDisplay,XWindow,XGraphicCTX,RDM&0xFFFF,(RDM>>16),64,64);
        }

        XFlush(XDisplay);

        usleep(16667); //AHHH there is 666!
    }

    return 0;
}

结果如下调整后

正如我们所见,只要设置 ResizeRedirectMask 就会发生裁剪,您甚至不需要响应事件就可以实现!
#if 语句切换为 false 给出了所需的行为 因为它会禁用 ResizeRedirectMask.
该特定程序不关心 window 的大小,我的大多数程序都需要知道大小,否则它会失败


一些细节:

曾经使用XGetWindowAttributes()得到window的大小,有点慢,我仍然在菜单中使用它 因为它很好用
这就是为什么在编辑器中,我使用 ResizeRequest 事件。

ConfigureNotify事件似乎效果很好,但它闪烁的方式比使用XGetWindowAttributes()要多得多。
为什么会闪烁?
闪烁是因为ConfigureNotify在调整完成后发送,这意味着它作为一般在调整后发送一帧。
这是 linked 到
至少不会浪费很多性能
我正在寻找一种方法来修复闪烁,因为它可能更容易。

请注意,问题完全改变了,因为问题与原来不同。但仍处于 link 原始问题中。

ResizeRedirectMask 与您的目的无关。除非您正在编写 window 管理器,否则您永远不需要它。你需要StructureNotifyMask。你几乎应该总是 select 这个面具(也许除非你的 window 永远不会调整大小)。

如果您不 select StructureNotifyMask,您的 window 永远不会收到实际的调整大小事件,也没有机会响应它们。

当你得到一个 ConfigureNotify 事件时,只有你 select StructureNotifyMask 才会发生,它会包含新的实际几何体,所以你的 window 可以更新本身。