为什么在 `XLookupColor()` 成功的情况下,`xcb_lookup_color()` 会失败?
我用这个代码来比较 XLookupColor() 和 xcb_lookup_color() 的差异:
#include <X11/Xlib.h>
#include <string.h>
#include <xcb/xcb.h>
#include <stdio.h>
int main(void)
{
const char *s = "#ff0000";
Display *display = XOpenDisplay(NULL);
XColor exact, screen_c;
printf("%d\n", XLookupColor(display, XDefaultColormap(display, XDefaultScreen(display)), s, &exact, &screen_c));
printf("rgb = %ld %ld %ld\n", exact.red, exact.green, exact.blue);
int screen_index;
xcb_connection_t *c = xcb_connect(NULL, &screen_index);
const xcb_setup_t *setup = xcb_get_setup(c);;
xcb_screen_t *screen;
xcb_screen_iterator_t iterator;
int i = screen_index;
for (iterator = xcb_setup_roots_iterator(setup);
iterator.rem > 0; i--, xcb_screen_next(&iterator)) {
if (i == 0) {
screen = iterator.data;
break;
}
}
xcb_lookup_color_cookie_t cookie = xcb_lookup_color(c, screen->default_colormap, strlen(s), s);
xcb_generic_error_t *error;
xcb_lookup_color_reply_t *reply = xcb_lookup_color_reply(c, cookie, &error);
if (reply == NULL) {
printf("error: %u\n", error->error_code);
}
return 0;
}
运行:cc a.c -lX11 -lxcb -o a.out ; ./a.out,
XLookupColor() 成功,我得到了正确的颜色。
xcb_lookup_color() 另一方面失败——也就是返回是 NULL,并带有错误15(对应名称错误)。当我把颜色字符串改成 "red" 时就能工作。这让我觉得 XLookupColor() 比 xcb_lookup_color() 做了更多工作。
手册页中关于 XLookupColor() 的说明指出,不鼓励继续使用 #... 语法,这意味着它们可能在 xcb 中放弃了对它的支持。
我需要手动处理基本的 #... 情况吗?
解决方案
这让我觉得XLookupColor() 的工作量比xcb_lookup_color() 多。
没错,你说对了。
查看源代码,XLookupColor() 首先做一些本地解析:https://github.com/mirror/libX11/blob/ff8706a5eae25b8bafce300527079f68a201d27f/src/LookupCol.c#L59
这似乎在本地处理 #(但我只找到了这一段代码,尚未完整跟踪整个流程):https://github.com/mirror/libX11/blob/ff8706a5eae25b8bafce300527079f68a201d27f/src/xcms/cmsColNm.c#L219
只有当这段解析失败,XLookupColor() 才会去询问X11服务器:https://github.com/mirror/libX11/blob/ff8706a5eae25b8bafce300527079f68a201d27f/src/LookupCol.c#L83
XCB在本地不做任何处理。它只是一个协议绑定。libxcb不会做你没有显式让它做的花哨事。
关于 xcb_lookup_color() 的代码是由代码生成器生成的,因此我无法轻易链接到它,但它确实只是将提供的参数序列化并发送给X11服务器:
xcb_lookup_color_cookie_t
xcb_lookup_color (xcb_connection_t *c,
xcb_colormap_t cmap,
uint16_t name_len,
const char *name)
{
static const xcb_protocol_request_t xcb_req = {
.count = 4,
.ext = 0,
.opcode = XCB_LOOKUP_COLOR,
.isvoid = 0
};
struct iovec xcb_parts[6];
xcb_lookup_color_cookie_t xcb_ret;
xcb_lookup_color_request_t xcb_out;
xcb_out.pad0 = 0;
xcb_out.cmap = cmap;
xcb_out.name_len = name_len;
memset(xcb_out.pad1, 0, 2);
xcb_parts[2].iov_base = (char *) &xcb_out;
xcb_parts[2].iov_len = sizeof(xcb_out);
xcb_parts[3].iov_base = 0;
xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;
/* char name */
xcb_parts[4].iov_base = (char *) name;
xcb_parts[4].iov_len = name_len * sizeof(char);
xcb_parts[5].iov_base = 0;
xcb_parts[5].iov_len = -xcb_parts[4].iov_len & 3;
xcb_ret.sequence = xcb_send_request(c, XCB_REQUEST_CHECKED, xcb_parts + 2, &xcb_req);
return xcb_ret;
}