Linux下获取屏幕信息,屏幕大小,工作区,任务栏等

最近工作中遇到一个小问题,就是需要获取屏幕工作区域以及任务栏区域,之前采用的其他三方库封装的接口,发现在开发测试过程中会存在工作区获取异常的问题,于是放弃第三方接口,采用原生X11/Xrandr实现。

因为使用XGetWindowProperty获取"_NET_WORKAREA"这个属性是获取的整个虚拟屏幕(多个屏幕组合)的区域,如果存在多扩展屏的情况则会有问题,所以实现思路如下:

1.  先使用XRRGetScreenResources获取所有屏幕信息

2. 使用XGetWindowProperty获取虚拟工作区

3. 计算主屏任务栏区域,并将主屏任务栏高度适用到其他副屏

具体代码实现如下:

struct Screen_t {
    std::string name;                       // 屏幕名称
    int index = -1;                         // 屏幕索引(一般0为主屏)
    int x, y = 0;                           // 屏幕位置
    int width, height = 0;                  // 屏幕分辨率
    int work_x, work_y = 0;                 // 工作区位置(相对于屏幕)
    int work_width, work_height = 0;        // 工作区大小
    int taskbar_x, taskbar_y = 0;           // 任务栏位置(相对于屏幕)
    int taskbar_width, taskbar_height = 0;  // 任务栏大小
};

std::vector<Screen_t> get_screen_infos(Display* display, Window root) {
        std::vector<Screen_t> screens;

        // 获取所有屏幕资源
        XRRScreenResources* res = XRRGetScreenResources(display, root);
        if (!res) {
            return screens;
        }

        // 获取当前活动输出
        XRROutputInfo* output_info;
        XRRCrtcInfo* crtc_info;

        // 获取所有屏幕的基本信息
        for (int i = 0; i < res->noutput; i++) {
            output_info = XRRGetOutputInfo(display, res, res->outputs[i]);
            if (output_info->connection == RR_Connected) {
                crtc_info = XRRGetCrtcInfo(display, res, output_info->crtc);

                // 屏幕信息
                Screen_t screen;
                screen.name = output_info->name;
                screen.index = i;
                screen.x = crtc_info->x;
                screen.y = crtc_info->y;
                screen.width = crtc_info->width;
                screen.height = crtc_info->height;

                // 初始化屏幕工作区信息
                screen.work_x = 0;
                screen.work_y = 0;
                screen.work_width = crtc_info->width;
                screen.work_height = crtc_info->height;

                // 初始化屏幕任务栏信息
                screen.taskbar_x = 0;
                screen.taskbar_y = 0;
                screen.taskbar_width = 0;
                screen.taskbar_height = 0;

                screens.push_back(screen);
                XRRFreeCrtcInfo(crtc_info);
            }
            XRRFreeOutputInfo(output_info);
        }

        // 获取当前显示工作区信息
        Atom actual_type;
        int actual_format;
        unsigned long nitems, bytes_after;
        unsigned char* data = NULL;
        Atom property = XInternAtom(display, "_NET_WORKAREA", False);

        if (XGetWindowProperty(display, root, property, 0, (~0L),
            False, AnyPropertyType, &actual_type,
            &actual_format, &nitems, &bytes_after,
            &data) == Success && data) {
            if (nitems >= 4) {
                long* workarea = (long*)data;

                // 计算主屏任务栏高度
                int primary_taskbar_height = 0;
                if (!screens.empty()) {
                    Screen_t& primary = screens[0];
                    long wa_bottom = workarea[1] + workarea[3];
                    primary_taskbar_height = primary.height - (wa_bottom - primary.y);

                    // 主屏任务栏信息(目前只考虑了任务栏在底部的情况)
                    primary.taskbar_x = 0;
                    primary.taskbar_y = primary.height - primary_taskbar_height;
                    primary.taskbar_width = primary.width;
                    primary.taskbar_height = primary_taskbar_height;
                }

                // 处理剩下屏幕
                for (auto& screen : screens) {
                    int screen_right = screen.x + screen.width;
                    int screen_bottom = screen.y + screen.height;
                    int wa_right = workarea[0] + workarea[2];
                    int wa_bottom = workarea[1] + workarea[3];

                    int intersect_x1 = std::max(screen.x, (int)workarea[0]);
                    int intersect_y1 = std::max(screen.y, (int)workarea[1]);
                    int intersect_x2 = std::min(screen_right, wa_right);
                    int intersect_y2 = std::min(screen_bottom, wa_bottom);

                    if (intersect_x1 < intersect_x2 && intersect_y1 < intersect_y2) {
                        // 计算工作区
                        screen.work_x = intersect_x1 - screen.x;
                        screen.work_y = intersect_y1 - screen.y;
                        screen.work_width = intersect_x2 - intersect_x1;
                        screen.work_height = intersect_y2 - intersect_y1;

                        // 默认使用主屏任务栏高度
                        if (screen.index != 0) {
                            screen.taskbar_x = 0;
                            screen.taskbar_y = screen.height - primary_taskbar_height;
                            screen.taskbar_width = screen.width;
                            screen.taskbar_height = primary_taskbar_height;

                            screen.work_height = screen.height - primary_taskbar_height - screen.work_y;
                        }
                    }
                }
            }
            XFree(data);
        }

        XRRFreeScreenResources(res);
        return screens;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值