简体   繁体   中英

X11: Getting bogus window size and position

I'm using Ubuntu 12.04 in a VM.

Upper left is never correct. Width and height are correct about 90% of the time.

XMoveWindow and friends have no effect on the rendered position of the window.

Source:

#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;
}

Note: There might be a spelling error to two, as pasting from within the VM wouldn't format correctly. As a result, I had to re-type it.

EDIT:

Because clarity is needed here: I don't care what the window manager does with the position I give it, I am interested in retrieving this information from the window manager reliably. The position I am given does not correspond to the rendered position of the window on the screen. For example: The window appears at the lower right of the screen, and the coordinates returned to me are (0,0) . Moving the window around using the mouse doesn't change what XGetWindowAttributes returns.

It seems you are polling window information from Expose event, which may not have newest information about window at the time. Use ConfigureNotify event and it's properties to get updated position and size:

// 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;

I think, one of the option is to use 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);

You also can use XGetGeometry instead of XGetWindowAttributes to get left, top, width and height of a drawable. As far as I know XGetWindowAttributes calls XGetGeometry to retrieve some of the attributes.

I know, I'm necroposter, but I was also looking for the answer and found out that the incorrect coordinates are related to Window Manager.

    {
    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

For the additional info you need to read ICCCM (4.1.5. Configuring the Window, 4.2.3. Window Move, 4.2.4. Window Resize) https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM