我正在尝试为 ubuntu 制作一个 C++ 程序,它获取鼠标悬停的像素的 rgb 值。为此,我需要
XGetImage()
函数,但它总是返回一个错误代码(不匹配)。
#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: %d\troot_y: %d\nchild_x: %d\tchild_y: %d\n",
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;
}
#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);
}
}
}
以下代码适用于我的系统(Arch、Gnome、双屏、Nvidia、No Xinerama - 根窗口大小 3840x1080 - 来自
XGetWindowAttributes
的正确值和来自 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;
}
}
编译:
gcc -Wall `pkg-config --cflags x11` -o main main.c `pkg-config --libs x11`
输出:
100 100 (0xABCDEF...)
来自XGetImage:
如果 drawable 是一个窗口,则该窗口必须是可见的,并且必须是这样的情况,即如果没有劣质或重叠的窗口,则窗口的指定矩形将在屏幕上完全可见并且完全包含在外边缘内的窗口,或 BadMatch 错误结果。 ...
诊断
BadMatch InputOnly 窗口用作 Drawable.
BadMatch 某些参数或参数对具有正确的类型和范围,但无法以请求所需的其他方式匹配。
作为结论,测试上面的最小代码。如果仍然出错,请查询树并测试后续窗口。
事实证明,
XGetImage()
需要一个当前在屏幕上可见的Window。我通过传递从函数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: %d\theight: %d\tx: %d\ty: %d\n", child_attr.width, child_attr.height, child_attr.x, child_attr.y);
std::printf("mouse_x: %d\tmouse_y: %d\n", 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: %d\ty_mouse_offset: %d\n", 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;
}