QT窗口无法激活弹出问题排查记录

问题背景

问题环境

复制代码
            操作系统: 银河麒麟V10SP1
            qt版本  : 5.12.12

碰见了一个问题应用最小化,然后激活程序窗口无法弹出

复制代码
            这里描述一下代码的逻辑,使用QLocalServer实现一个单例进程,
            具体的功能就是在已存在一个程序A进程时,再启动这个程序A,新的程序A进程会被杀死,然后激活已存在的进程,使窗口弹出

跟踪代码发现走到了激活函数(如下所示)

复制代码
            this->raise();
            this->activateWindow();
复制代码
问题现象如下,确实是有激活效果,图标闪烁了,但是窗口在最小化的情况不会弹

排查过程

首先,我想写个简易的demo来复现这个问题,但是下面所示的代码并不能复现出上面提到的问题,最小化窗口可以被激活弹出,所以我还是得用原来的代码进行排查

复制代码
              MainWindow::MainWindow(QWidget *parent)
              : QMainWindow(parent)
              , ui(new Ui::MainWindow){
              ui->setupUi(this);
              //使用定时器触发执行槽函数
              QObject::connect(&m_timer, &QTimer::timeout, this,&MainWindow::slottimer);
            }

            MainWindow::~MainWindow(){
              delete ui;
            }

            //3秒钟执行一次
            void MainWindow::on_pushButton_clicked(){
              m_timer.start(3000);
            }

            //激活窗口
            void MainWindow::slottimer(){
              this->raise();
              this->activateWindow();
            }

为了排除操作系统的影响,我选择用同一份代码在不同系统上测试一下,看看效果

这里我测试了kylin、ubuntu都有这种问题,说明大概率和操作系统无关,uos因为操作系统镜像不好下载我就没测

和系统没关系,执行的时候也走了对应的函数,那么现在只能跟踪qt代码看看为什么没有弹出了,跟踪后有如下发现

复制代码
            最后进入了QXcbWindow::requestActivateWindow()函数

            执行xcb_send_event(xcb_connection(), 
                               0, 
                               xcbScreen()->root(),
                               XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
                               (const char *)&event);

可以看到激活窗口实际是调用xcb模块的功能

复制代码
            xcb介绍,XCB是X协议的一个C语言绑定,它提供了一种更现代、更高效的方式来与X Window System进行交互。

            xcb官网  https://xcb.freedesktop.org/

我分别在使用wayland和X协议的系统上进行测试,最后代码都走到了xcb_send_event方法

接下来我就开始尝试对xcb_send_event的传参进行修改,重点是修改第二和第四个传参,其实这一步修改就是瞎改,也没有什么修改逻辑,我做的尝试如下:

复制代码
            0  ->  1
            XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT  在此基础上增加或者减少事件掩码

在修改测试过程中,发现偶尔能弹出来,但概率很低,然后我再把参数都恢复,发现也能偶尔弹出来,此刻我感觉和修改xcb_send_event参数没有什么关系了

再结合前面我自己写的demo可以正常弹出的情况,我觉得代码中使用QLocalServer实现单例进程并且杀死新进程的方法可能会造成激活窗口操作失效(纯猜测,但改变了我的解决思路)

所以还是要从应用调用代码的角度去解决


解决方案

如上所述,激活窗口一次没有没有生效,是不是多执行几次激活是不是就可以了?

所以我修改激活窗口的方式,在原先激活窗口的位置开启定时器(定时器触发时间间隔500Ms~2s即可),在槽函数中执行激活窗口操作,当窗口激活成功就停止定时器

在测试中发现,定时器第一次触发激活窗口的现象只是任务栏的图标闪烁,但窗口不弹出,而在第二次触发时窗口从任务栏中弹出,一般情况下第二次触发就能弹出了


后记

为什么第一次触发激活窗口没有成功?目前还没有找到根源,我猜测可能是因为起第二进程再杀死导致了一些时序错误或者影响了堆栈,后续还要验证

如果单纯从解决窗口不弹出的角度来说,还有一个方法就是调用命令wmctrl,但也可能存在失效的问题

复制代码
            QProcess myProcess;
            QString program = "wmctrl";
            QStringList arguments;
            arguments << "-a" << w->windowTitle();

            myProcess.start(program,arguments);
            myProcess.waitForFinished();
相关推荐
艾莉丝努力练剑1 小时前
【QT】Qt常用控件与布局管理深度解析:从原理到实践的架构思考
linux·运维·服务器·开发语言·网络·qt·架构
Z文的博客1 小时前
嵌入式 ARM 设备交叉编译 mosquitto 2.0.20 (完整 TLS 支持) 详细教程 TRAE全程辅助,没敲一行代码
qt·mqtt·嵌入式·ai编程·mosquitto·嵌入式linux·trae
特立独行的猫a1 小时前
HarmonyOS 鸿蒙PC端 Qt 应用开发:第三方 Qt 开源软件移植指南
qt·harmonyos·鸿蒙·鸿蒙pc
C++ 老炮儿的技术栈11 小时前
GCC编译时无法向/tmp 目录写入临时汇编文件,因为设备空间不足,解决
linux·运维·开发语言·汇编·c++·git·qt
米优15 小时前
qt+vlc实现国标客户端测试工具
qt·gb28181·vlc
米优16 小时前
qt+vlc实现解码h264/h265裸码流播放
开发语言·qt·vlc
小小码农Come on17 小时前
QT面试题总结
开发语言·qt
特立独行的猫a17 小时前
HarmonyOS鸿蒙PC的QT应用开发:(二、开发环境搭建及第一个HelloWorld)
qt·华为·harmonyos·鸿蒙·鸿蒙pc
史迪仔011217 小时前
[QML] QT5和QT6 圆角的不同设置方法
前端·javascript·qt
一只小小的土拨鼠18 小时前
【避坑指南】Qt + MSVC + CUDA 项目链接与发布报错全记录
开发语言·qt