【问题标题】:X11: Getting bogus window size and positionX11:获取虚假的窗口大小和位置
【发布时间】:2013-01-17 08:27:03
【问题描述】:

我在虚拟机中使用 Ubuntu 12.04。

左上角永远不正确。大约 90% 的时间宽度和高度都是正确的。

XMoveWindow和好友对窗口的渲染位置没有影响。

来源:

#include <stdio.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/X.h>

int main(int argc, char **argv)
{
    Display *disp = XOpenDisplay(0);

    GLint attr[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GX_DOUBLEBUFFER, None};
    XVisualInfo *vinfo = glXChooseVisual(disp,0,attr);

    Window rootWnd = DefaultRootWindow(disp);

    XSetWindowAttributes setWndAttr = {0};
    setWndAttr.colormap = XCreateColormap(disp,rootWnd,vinfo->visual,AllocNone);
    setWndAttr.event_mask =
        ExposureMask|
        StructureNotifyMask;

    Window wnd = XCreateWindow(
        disp,rootWnd,
        64,64,  // can be ignored (asinine)
        512,512,
        0,vinfo->depth,
        InputOutput,
        vinfo->visual,
        CWColormap|CWEventMask,
        &setWndAttr
        );

    XStoreName(disp,wnd,"What is this crap?");
    XMapWindow(disp,wnd);

    // WMs allowed to completely ignore these, too?
    //XMoveWindow(disp,wnd,128,128);
    //XMoveResizeWindow(disp,wnd,128,128,256,256);

    Atom closeWndAtom = XInternAtom(disp,"WM_DELETE_WINDOW",0);
    XSetWMProtocols(disp,wnd,&closeWndAtom,1);

    GLXContext ctx = glCreateContext(disp,vinfo,0,GL_TRUE);
    glXMakeCurrent(disp,wnd,ctx);

    bool run = true;
    XEvent evt;
    while(run){
        XNextEvent(disp,&evt);
        switch(evt.type){
        case Expose:
            {
                XWindowAttributes wndAttr;
                XGetWindowAttributes(disp,wnd,&wndAttr);

                // these are NEVER correct (0,0 most of the time)
                printf("%i, %i\n",wndAttr.x,wndAttr.y);

                // these are correct, most of the time
                //
                // occasionally, either width or height will be 0
                glViewport(0,0,wndAttr.width,wndAttr.height);

                glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
                glBegin(GL_TRIANGLES);
                glColor3f(1,0,0);
                glVertex2f(0,0);
                glColor3f(0,1,0);
                glVertex2f(1,0);
                glColor3f(0,0,1);
                glVertex2f(0,1);
                glEnd();

                glXSwapBuffers(disp,wnd);
            }break;
        case ClientMessage:
            {
                run = false;
            }break;
        }
    }

    glXDestroyContext(disp,ctx);
    XDestroyWindow(disp,wnd);
    XCloseDisplay(disp);
    return 0;
}

注意:两个可能存在拼写错误,因为从 VM 中粘贴的格式不正确。结果,我不得不重新输入。

编辑:

因为这里需要明确:我不在乎窗口管理器对我给它的位置做了什么,我有兴趣从窗口管理器可靠地检索此信息。我给出的位置与屏幕上窗口的渲染位置不对应。例如:屏幕右下方出现窗口,返回给我的坐标是(0,0)。使用鼠标移动窗口不会改变XGetWindowAttributes 返回的内容。

【问题讨论】:

  • 我的建议是永远不要直接使用 xlib,而是使用现有的框架之一。 SDLSFML(当然还有其他)都很小,让您只需一两行即可创建一个支持 OpenGL 的窗口。
  • 1:SDL、Qt 和其他是我不能允许的依赖项。 2:应该可以基于现有文档编写一个独立的 UI 库。 3:Xlib 不是(绝不能)只供那些希望“推销”跨平台 UI 工具包的人访问。 4:我鄙视基于 OO 的 UI 工具包。
  • 如何编译?你有什么问题?
  • 问题是:为什么XGetWindowAttributes 会产生不正确的值?是窗口管理器的原因吗?是我做的吗?我不知道,这就是我在这里问的原因。
  • 那我建议你也为resize request events加一个case。

标签: c++ x11


【解决方案1】:

您似乎正在从 Expose 事件中轮询窗口信息,该事件当时可能没有有关窗口的最新信息。使用 ConfigureNotify 事件及其属性来获取更新的位置和大小:

// you need to have this in your event mask(you've already got that):
EVENT_MASK |= StructureNotifyMask;

// in your event loop
// ...
case ConfigureNotify: // resize or move event
    printf("x: %d, y:%d, width: %d, height: %d\n", 
           event.xconfigure.x,
           event.xconfigure.y,
           event.xconfigure.width,
           event.xconfigure.height);
    break;

【讨论】:

    【解决方案2】:

    我认为,一种选择是使用 XTranslateCoordinates

    XTranslateCoordinates(dpy,
                          wnd,         // get position for this window
                          root_window, // something like macro: DefaultRootWindow(dpy)
                          0, 0,        // local left top coordinates of the wnd
                          &dest_x,     // these is position of wnd in root_window
                          &dest_y,     // ...
                          &unused);
    

    您也可以使用 XGetGeometry 代替 XGetWindowAttributes 来获取左、上、宽和高可绘制的。据我所知,XGetWindowAttributes 调用 XGetGeometry 来检索一些属性。

    【讨论】:

    【解决方案3】:

    我知道,我是necroposter,但我也在寻找答案,发现不正确的坐标与窗口管理器有关。

        {
        case ConfigureNotify :
            printf("%d, %d : %u, %u\n",
                    event.xconfigure.x, event.xconfigure.y,
                    event.xconfigure.width, event.xconfigure.height);
            break;
        }
    
    # Moving window
    353, 100 : 791, 600
    363, 113 : 791, 600
    # Changing window size
    1, 24 : 791, 600 << Pay attention to this
    363, 113 : 791, 600
    363, 113 : 791, 600
    

    有关其他信息,您需要阅读 ICCCM(4.1.5. 配置窗口,4.2.3. 窗口移动,4.2.4. 窗口调整大小)https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-24
      • 2015-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-07
      相关资源
      最近更新 更多