skip to Main Content

I’m trying to make a C++ Program for ubuntu which gets the rgb values of the Pixel hovered by the Mouse. To do that I need the XGetImage() function but it always returns an Error code (Badmatch).

#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>


int main(int, char**) {
    XColor c;
    Display *display = XOpenDisplay((char *) NULL);
    Window root = XRootWindow(display, XDefaultScreen(display));
    XWindowAttributes attr;
    XGetWindowAttributes(display, root, &attr);
    XMapRaised(display, root);
    unsigned int width = attr.width;
    unsigned int height = attr.height;
    root = attr.root;
    /*
    XQueryPointer(display, win, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask_return);
    std::printf("root_x: %dtroot_y: %dnchild_x: %dtchild_y: %dn",
        root_x,
        root_y,
        win_x,
        win_y
    );*/
    XMapRaised(display, root);
    XImage *image = XGetImage(display, root, 0, 0, 100, 100, AllPlanes, ZPixmap);
    c.pixel = XGetPixel(image, 0, 0);
    std::cout << c.red << std::endl;
    XFree(image);
    XQueryColor(display, XDefaultColormap(display, XDefaultScreen(display)), &c);
    std::cout << c.red << " " << c.green << " " << c.blue << std::endl;
    XCloseDisplay(display);
    return 0;
} 

Edit 1

I tested the minimal Example given below but it still throws an Error. So I decided to query all child Windows and tried to iterate through them backwards. But the first child already caused an error as well.

#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>


int main(int, char**) {
    //XColor c;
    Display *display = XOpenDisplay(NULL);
    Window root = DefaultRootWindow(display);
    Window root_root, parent;
    Window *children;
    unsigned int returned_children;
    XQueryTree(display, root, &root_root, &parent, &children, &returned_children);
    for (int i = returned_children -1; i >= 0; i--) {
        std::cout << i << std::endl;
        XImage *image = XGetImage(display, root, 0, 0, 100, 100, AllPlanes, ZPixmap);
        if (image) {
            std::printf("%d %d (%p)n", image->width, image->height, image->data);
        }
    }
}

2

Answers


  1. Chosen as BEST ANSWER

    It turns out that XGetImage() needs a Window that is currently visible on the screen. I solved the Problem by passing the child Window queried from the function XQueryPointer().

    int main(int, char**) {
        XColor c;
        Display *display = XOpenDisplay(NULL);
        Window root = DefaultRootWindow(display);
    
        Window child, root_win;
        int root_x, root_y, win_x, win_y;
        unsigned int mask_return;
        XQueryPointer(display, root, &root_win, &child, &root_x, &root_y, &win_x, &win_y, &mask_return);
        
    
        XWindowAttributes child_attr;
        XGetWindowAttributes(display, child, &child_attr);
        std::printf("width: %dtheight: %dtx: %dty: %dn", child_attr.width, child_attr.height, child_attr.x, child_attr.y);
        std::printf("mouse_x: %dtmouse_y: %dn", win_x, win_y);
    
        int x_mouse_offset = win_x - child_attr.x;
        int y_mouse_offset = win_y - child_attr.y;
        std::printf("x_mouse_offset: %dty_mouse_offset: %dn", x_mouse_offset, y_mouse_offset);
        XImage *image = XGetImage(display, child, x_mouse_offset, y_mouse_offset, 1, 1, AllPlanes, XYPixmap);
        if (!image) {
            perror("no image returned");
            return 1;
        }
        
        std::printf("image: %d %d (%p)n", image->width, image->height, image->data);
        c.pixel = XGetPixel(image, 0, 0);
        Colormap cm = DefaultColormap(display, child);
        XQueryColor(display, cm, &c);
        std::cout << c.red << " " << c.green << " " << c.blue << "n";
        XCloseDisplay(display);
       return 0;
    }
    

  2. The following code works on my system (Arch, Gnome, Dual Screen, Nvidia, No Xinerama – root window size 3840×1080 – correct values from XGetWindowAttributes and same image size from XGetImage):

    #include <stdio.h>
    #include <X11/Xlib.h>
    
    int main()
    {
        Display *display = XOpenDisplay(NULL);
        Window root = DefaultRootWindow(display);
    
        /* uncomment if geometry is needed
        XWindowAttributes attr;
        XGetWindowAttributes(display, root, &attr);
        int width = attr.width;
        int height = attr.height;*/
    
        XImage *image = XGetImage(display, root, 0, 0 , 100, 100, AllPlanes, ZPixmap);
    
        if (image) {
            printf("%d %d (%p)n", image->width, image->height, image->data);
            return 0;
        } else {
            printf("error");
            return -1;
        }
    }
    

    Compilation:

    gcc -Wall `pkg-config --cflags x11` -o main main.c `pkg-config --libs x11`
    

    Output:

    100 100 (0xABCDEF...)
    

    From XGetImage:

    If the drawable is a window, the window must be viewable, and it must be the case that if there were no inferiors or overlapping windows, the specified rectangle of the window would be fully visible on the screen and wholly contained within the outside edges of the window, or a BadMatch error results. …

    Diagnostics

    BadMatch An InputOnly window is used as a Drawable.

    BadMatch Some argument or pair of arguments has the correct type and range but fails to match in some other way required by the request.

    As a conclusion, test the minimal code above. If you still get errors, query the tree and test the subsequent windows.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search