如何在C++程序中无需轮询获取显示器变更通知?
无需轮询监听显示器连接状态变更(基于libXrandr)
当然可以通过事件驱动的方式替代轮询,利用Xrandr扩展的事件通知机制,在显示器连接/断开或配置变更时主动接收通知,无需定时查询。以下是具体实现思路和代码示例:
核心思路
Xrandr扩展提供了RRNotify事件,当显示设备的连接状态、分辨率等配置发生变化时,X服务器会向注册了监听的客户端发送该事件。只需完成以下三步:
- 初始化X连接并确认RandR扩展可用
- 注册监听RandR相关事件
- 在X事件循环中处理
RRNotify事件,触发显示器信息更新
代码实现示例
#include <X11/Xlib.h> #include <X11/extensions/Xrandr.h> #include <iostream> int main() { // 打开X显示连接 Display* dpy = XOpenDisplay(nullptr); if (!dpy) { std::cerr << "无法打开X显示连接" << std::endl; return 1; } // 检查RandR扩展是否可用 int event_base, error_base; if (!XRRQueryExtension(dpy, &event_base, &error_base)) { std::cerr << "系统不支持RandR扩展" << std::endl; XCloseDisplay(dpy); return 1; } // 启用RandR事件监听:注册根窗口的RRNotify事件 Window root_win = DefaultRootWindow(dpy); XRRSelectInput(dpy, root_win, RRNotifyMask); // X事件循环 XEvent ev; while (XNextEvent(dpy, &ev)) { // 判断是否为RandR通知事件 if (ev.type == event_base + RRNotify) { XRROutputChangeNotifyEvent* rr_event = reinterpret_cast<XRROutputChangeNotifyEvent*>(&ev); // 仅处理输出设备连接状态变更的事件 if (rr_event->subtype == RRNotifyOutputChange) { std::cout << "显示器连接状态发生变化,重新查询设备信息..." << std::endl; // 获取当前屏幕资源 XRRScreenResources* screen_res = XRRGetScreenResourcesCurrent(dpy, root_win); if (!screen_res) continue; // 遍历所有输出设备 for (int i = 0; i < screen_res->noutput; ++i) { XRROutputInfo* output_info = XRRGetOutputInfo(dpy, screen_res, screen_res->outputs[i]); if (!output_info) continue; // 输出设备连接状态 const char* conn_status = (output_info->connection == RR_Connected) ? "已连接" : "已断开"; std::cout << "输出设备 " << output_info->name << ": " << conn_status << std::endl; // 如果设备已连接,输出可用分辨率 if (output_info->connection == RR_Connected && output_info->ncrtc > 0) { XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(dpy, screen_res, output_info->crtc); if (crtc_info) { std::cout << "当前分辨率: " << crtc_info->width << "x" << crtc_info->height << std::endl; XRRFreeCrtcInfo(crtc_info); } } XRRFreeOutputInfo(output_info); } XRRFreeScreenResources(screen_res); std::cout << "------------------------" << std::endl; } } // 可在此处理其他X事件(如窗口事件等) } XCloseDisplay(dpy); return 0; }
关键说明
- 事件注册:通过
XRRSelectInput注册RRNotifyMask,告诉X服务器需要接收RandR相关的所有通知事件。 - 事件解析:
RRNotify事件包含多种子类型,其中RRNotifyOutputChange对应输出设备的连接/断开状态变更;若需监听分辨率切换,可关注RRNotifyScreenChange子类型。 - 内存管理:所有通过Xrandr函数获取的资源(如
XRRScreenResources、XRROutputInfo等)必须调用对应的Free函数释放,避免内存泄漏。 - 版本兼容性:不同版本的RandR扩展可能在事件结构或常量定义上有细微差异,建议针对目标系统的RandR版本做适配。
内容的提问来源于stack exchange,提问作者ataraxis
相关产品推荐
相关产品推荐

