如何使用Xlib实现应用程序直接在根窗口上绘制内容?
Xlib在根窗口绘制内容的实现方法
核心实现步骤
- 第一步连接X服务器,调用
XOpenDisplay(NULL)即可,参数为NULL时会自动读取系统DISPLAY环境变量连接默认X服务 - 调用
DefaultRootWindow(display)获取当前屏幕的根窗口ID,这就是你要绘制的目标载体 - 可提前调用
XGetGeometry接口获取根窗口的宽、高、色深等属性,方便计算绘制坐标适配不同分辨率
图形上下文(GC)配置
绘制前需要先创建GC存储绘制参数:
- 调用
XCreateGC(display, root_window, 0, NULL)创建GC对象 - 按需配置绘制属性:用
XSetLineAttributes设置线宽、线型,用XSetForeground/XSetBackground设置绘制颜色,颜色值可以通过XAllocNamedColor从系统色表分配,也可以直接传入对应色深的RGB数值 - 如果需要监听根窗口的重绘事件,调用
XSelectInput(display, root_window, ExposureMask),这样根窗口被覆盖后重新显示时你会收到Expose事件,方便同步重绘你的内容
绘制实现
直接调用Xlib标准绘制接口即可,所有接口的目标窗口参数都传入之前获取的根窗口ID:
- 画线条用
XDrawLine(display, root_window, gc, x1, y1, x2, y2) - 其他绘制接口比如
XDrawRectangle(矩形)、XDrawArc(圆弧)、XDrawString(文字)都可以直接使用 - 每次绘制完成后调用
XFlush(display)把绘制指令同步到X服务器,避免指令缓存导致绘制不生效 - 因为桌面壁纸、桌面图标程序也会向根窗口绘制内容,建议加定时器定期重绘你的内容,避免被其他程序的绘制操作覆盖
最小可运行示例代码
#include <X11/Xlib.h> #include <unistd.h> int main() { // 连接X服务器 Display *dpy = XOpenDisplay(NULL); if (!dpy) return 1; // 获取根窗口 Window root_win = DefaultRootWindow(dpy); // 监听根窗口重绘事件 XSelectInput(dpy, root_win, ExposureMask); // 创建GC并配置绘制参数:2像素宽实线,红色前景 GC draw_gc = XCreateGC(dpy, root_win, 0, NULL); XSetLineAttributes(dpy, draw_gc, 2, LineSolid, CapButt, JoinMiter); XSetForeground(dpy, draw_gc, 0xFF0000); // 24位色深下对应红色 XEvent event; while (1) { // 处理所有待处理的X事件 while (XPending(dpy)) { XNextEvent(dpy, &event); if (event.type == Expose) { // 根窗口需要重绘时重新画线条 XDrawLine(dpy, root_win, draw_gc, 100, 100, 600, 600); XFlush(dpy); } } // 每秒定期重绘,避免被其他桌面程序覆盖 XDrawLine(dpy, root_win, draw_gc, 100, 100, 600, 600); XFlush(dpy); sleep(1); } // 运行到此处时释放资源 XFreeGC(dpy, draw_gc); XCloseDisplay(dpy); return 0; }
编译命令:gcc 源码文件名.c -o 输出程序名 -lX11
注意事项
- 如果你的桌面环境开启了合成管理器(GNOME、KDE等主流桌面默认开启),根窗口会被合成器接管,直接绘制的内容可能不可见,这种情况可以关闭合成器测试,或者改为创建一个
override_redirect属性为True的子窗口,设置透明属性后放在桌面最底层,在这个子窗口上绘制兼容性更好 - 所有X资源使用完后要主动释放,避免出现资源泄漏
内容的提问来源于stack exchange,提问作者User
相关产品推荐
相关产品推荐

