You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++程序中无需轮询获取显示器变更通知?

无需轮询监听显示器连接状态变更(基于libXrandr)

当然可以通过事件驱动的方式替代轮询,利用Xrandr扩展的事件通知机制,在显示器连接/断开或配置变更时主动接收通知,无需定时查询。以下是具体实现思路和代码示例:

核心思路

Xrandr扩展提供了RRNotify事件,当显示设备的连接状态、分辨率等配置发生变化时,X服务器会向注册了监听的客户端发送该事件。只需完成以下三步:

  1. 初始化X连接并确认RandR扩展可用
  2. 注册监听RandR相关事件
  3. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 04:15:48