OpenKylin文件管理器界面层级切换问题
开发环境
操作系统: OpenKylinqt版本 : 5.15.10
问题描述
在使用wayland环境下,被遮挡住的界面在右键点击新标签中打开后,界面依旧被遮挡住了
在使用xcb环境下,现象是正常的
排查过程
从视频的现象上看,分析可能是右边界面因为某种原因又覆盖在左侧界面上,所以优先去排查是什么原因导致右边界面自动覆盖的
从上到下的排查顺序是 : 应用代码->Qt源码->Qt源码(qt处理 xcb或wayland 事件的逻辑)
首先是从源码去排查,在代码中找QApplication::activeWindow(),找了几个位置的代码,注释掉之后发现没有什么变化,应该不是应用代码的问题
其次整个问题应该是属于事件传递、处理类型的,不算是控件功能类的,所以Qt源码中的控件类代码不需要进行排查(其实这一步还是耗费了一些时间,但没有什么收获,就不展开了)
那么最后就要去排查xcb、wayland是否传递事件有差异,或者说是qt处理事件有差异,这一部分需要用gdb调试去看,不同环境下qt处理事件的路径
====两种环境运行的堆栈====XCB环境#0 QApplicationPrivate::notifyActiveWindowChange (this=0x7f133f0, previous=0x8d26980) at kernel/qapplication.cpp:2098#1 0x00007fa83133b275 in QGuiApplicationPrivate::processActivatedEvent (e=) at kernel/qguiapplication.cpp:2515#2 0x00007fa83131209c in QWindowSystemInterface::sendWindowSystemEvents (flags=flags@entry=...) at kernel/qwindowsysteminterface.cpp:1169#3 0x00007fa827afb75a in 【xcbSourceDispatch】 (source=) at ./src/plugins/platforms/xcb/qxcbeventdispatcher.cpp:105#4 0x00007fa832ac1847 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#5 0x00007fa832b1935f in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#6 0x00007fa832ac0d7c in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#7 0x00007fa830d0a016 in QEventDispatcherGlib::processEvents (this=0x8055c60, flags=...) at kernel/qeventdispatcher_glib.cpp:423#8 0x00007fa830cb0f6b in QEventLoop::exec (this=this@entry=0x7ffdb5a36290, flags=..., flags@entry=...)at ../../include/QtCore/../../src/corelib/global/qflags.h:69#9 0x00007fa830cb90c6 in QCoreApplication::exec () at ../../include/QtCore/../../src/corelib/global/qflags.h:121#10 0x00000000004432da in main ()---#0 QApplicationPrivate::openPopup (this=0x7f133f0, popup=popup@entry=0x7ffdb5a356f0) at kernel/qapplication.cpp:3756#1 0x00007fa831ba1d90 in QWidgetPrivate::show_helper (this=this@entry=0x8e0a760) at kernel/qwidget.cpp:7848#2 0x00007fa831ba4ae3 in QWidgetPrivate::setVisible (this=0x8e0a760, visible=) at kernel/qwidget.cpp:8141#3 0x00007fa831ce892d in QMenuPrivate::popup(QPoint const&, QAction*, std::function)(this=this@entry=0x8e0a760, p=..., atAction=atAction@entry=0x0, positionFunction=...) at widgets/qmenu.cpp:2640#4 0x00007fa831ce995a in QMenuPrivate::exec(QPoint const&, QAction*, std::function)(this=0x8e0a760, p=..., action=0x0, positionFunction=...) at widgets/qmenu.cpp:2720#5 0x00007fa831ce9aaf in QMenu::exec (this=, p=, action=) at widgets/qmenu.cpp:2710#6 0x0000000000483371 in ??? ()#7 0x00007fa830ce978f in QtPrivate::QSlotObjectBase::call (a=0x7ffdb5a35840, r=0x8721fd0, this=0x876fff0)at ../../include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398#8 doActivate (sender=0x8721fd0, signal_index=6, argv=0x7ffdb5a35840) at kernel/qobject.cpp:3925#9 0x00007fa830ce2a7f in QMetaObject::activate(sender=sender@entry=0x8721fd0, m=m@entry=0x7fa83207c0a0 , local_signal_index=local_signal_index@entry=3, argv=argv@entry=0x7ffdb5a35840) at kernel/qobject.cpp:3985#10 0x00007fa831b8a435 in QWidget::customContextMenuRequested (this=this@entry=0x8721fd0, _t1=...) at .moc/moc_qwidget.cpp:653#11 0x00007fa831ba5dd3 in QWidget::event (this=this@entry=0x8721fd0, event=event@entry=0x7ffdb5a35c70) at kernel/qwidget.cpp:8856#12 0x00007fa831c5092e in QFrame::event (this=0x8721fd0, e=0x7ffdb5a35c70) at widgets/qframe.cpp:550#13 0x00007fa830cb226b in QCoreApplicationPrivate::sendThroughObjectEventFilters(receiver=receiver@entry=0x874b9f0, event=event@entry=0x7ffdb5a35c70) at kernel/qcoreapplication.cpp:1190#14 0x00007fa831b62fee in QApplicationPrivate::notify_helper(this=this@entry=0x7f133f0, receiver=receiver@entry=0x874b9f0, e=e@entry=0x7ffdb5a35c70) at kernel/qapplication.cpp:3639#15 0x00007fa831b6a600 in QApplication::notify (this=, receiver=0x874b9f0, e=) at kernel/qapplication.cpp:3251#16 0x00007fa830cb24e8 in QCoreApplication::notifyInternal2 (receiver=0x874b9f0, event=0x7ffdb5a35c70) at kernel/qcoreapplication.cpp:1064#17 0x00007fa830cb2532 in QCoreApplication::forwardEvent (receiver=, event=, originatingEvent=)at kernel/qcoreapplication.cpp:1079#18 0x00007fa831bbebc9 in QWidgetWindow::handleMouseEvent (this=this@entry=0x87caa30, event=event@entry=0x7ffdb5a35f60)at kernel/qwidgetwindow.cpp:692#19 0x00007fa831bc15f0 in QWidgetWindow::event (this=0x87caa30, event=0x7ffdb5a35f60) at kernel/qwidgetwindow.cpp:300#20 0x00007fa831b62ffe in QApplicationPrivate::notify_helper (this=, receiver=0x87caa30, e=0x7ffdb5a35f60)at kernel/qapplication.cpp:3645#21 0x00007fa830cb24e8 in QCoreApplication::notifyInternal2 (receiver=0x87caa30, event=0x7ffdb5a35f60) at kernel/qcoreapplication.cpp:1064#22 0x00007fa830cb26be in QCoreApplication::sendSpontaneousEvent (receiver=, event=)at kernel/qcoreapplication.cpp:1474#23 0x00007fa83133ef7d in QGuiApplicationPrivate::processMouseEvent (e=0x8e093a0) at kernel/qguiapplication.cpp:2282#24 0x00007fa83131209c in QWindowSystemInterface::sendWindowSystemEvents (flags=flags@entry=...) at kernel/qwindowsysteminterface.cpp:1169#25 0x00007fa827afb75a in 【xcbSourceDispatch】 (source=) at ./src/plugins/platforms/xcb/qxcbeventdispatcher.cpp:105#26 0x00007fa832ac1847 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#27 0x00007fa832b1935f in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#28 0x00007fa832ac0d7c in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#29 0x00007fa830d0a016 in QEventDispatcherGlib::processEvents (this=0x8055c60, flags=...) at kernel/qeventdispatcher_glib.cpp:423#30 0x00007fa830cb0f6b in QEventLoop::exec (this=this@entry=0x7ffdb5a36290, flags=..., flags@entry=...)===============================================================================================================================================WAYLAND#0 QApplicationPrivate::openPopup (this=0x48284f0, popup=popup@entry=0x7ffff9d38be0) at kernel/qapplication.cpp:3756#1 0x00007f75655a1d90 in QWidgetPrivate::show_helper (this=this@entry=0x54fc510) at kernel/qwidget.cpp:7848#2 0x00007f75655a4ae3 in QWidgetPrivate::setVisible (this=0x54fc510, visible=) at kernel/qwidget.cpp:8141#3 0x00007f75656e892d in QMenuPrivate::popup(QPoint const&, QAction*, std::function)(this=this@entry=0x54fc510, p=..., atAction=atAction@entry=0x0, positionFunction=...) at widgets/qmenu.cpp:2640#4 0x00007f75656e995a in QMenuPrivate::exec(QPoint const&, QAction*, std::function)(this=0x54fc510, p=..., action=0x0, positionFunction=...) at widgets/qmenu.cpp:2720#5 0x00007f75656e9aaf in QMenu::exec (this=, p=, action=) at widgets/qmenu.cpp:2710#6 0x0000000000483371 in ??? ()#7 0x00007f75646e978f in QtPrivate::QSlotObjectBase::call (a=0x7ffff9d38d30, r=0x4e422a0, this=0x4e7f0a0)at ../../include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398#8 doActivate (sender=0x4e422a0, signal_index=6, argv=0x7ffff9d38d30) at kernel/qobject.cpp:3925#9 0x00007f75646e2a7f in QMetaObject::activate(sender=sender@entry=0x4e422a0, m=m@entry=0x7f7565a7c0a0 , local_signal_index=local_signal_index@entry=3, argv=argv@entry=0x7ffff9d38d30) at kernel/qobject.cpp:3985#10 0x00007f756558a435 in QWidget::customContextMenuRequested (this=this@entry=0x4e422a0, _t1=...) at .moc/moc_qwidget.cpp:653#11 0x00007f75655a5dd3 in QWidget::event (this=this@entry=0x4e422a0, event=event@entry=0x7ffff9d39160) at kernel/qwidget.cpp:8856#12 0x00007f756565092e in QFrame::event (this=0x4e422a0, e=0x7ffff9d39160) at widgets/qframe.cpp:550#13 0x00007f75646b226b in QCoreApplicationPrivate::sendThroughObjectEventFilters(receiver=receiver@entry=0x4e6cf70, event=event@entry=0x7ffff9d39160) at kernel/qcoreapplication.cpp:1190#14 0x00007f7565562fee in QApplicationPrivate::notify_helper(this=this@entry=0x48284f0, receiver=receiver@entry=0x4e6cf70, e=e@entry=0x7ffff9d39160) at kernel/qapplication.cpp:3639#15 0x00007f756556a600 in QApplication::notify (this=, receiver=0x4e6cf70, e=) at kernel/qapplication.cpp:3251#16 0x00007f75646b24e8 in QCoreApplication::notifyInternal2 (receiver=0x4e6cf70, event=0x7ffff9d39160) at kernel/qcoreapplication.cpp:1064#17 0x00007f75646b2532 in QCoreApplication::forwardEvent (receiver=, event=, originatingEvent=)at kernel/qcoreapplication.cpp:1079#18 0x00007f75655bebc9 in QWidgetWindow::handleMouseEvent (this=this@entry=0x4f75e70, event=event@entry=0x7ffff9d39450)at kernel/qwidgetwindow.cpp:692#19 0x00007f75655c15f0 in QWidgetWindow::event (this=0x4f75e70, event=0x7ffff9d39450) at kernel/qwidgetwindow.cpp:300#20 0x00007f7565562ffe in QApplicationPrivate::notify_helper (this=, receiver=0x4f75e70, e=0x7ffff9d39450)at kernel/qapplication.cpp:3645#21 0x00007f75646b24e8 in QCoreApplication::notifyInternal2 (receiver=0x4f75e70, event=0x7ffff9d39450) at kernel/qcoreapplication.cpp:1064#22 0x00007f75646b26be in QCoreApplication::sendSpontaneousEvent (receiver=, event=)at kernel/qcoreapplication.cpp:1474#23 0x00007f7564d3ef7d in QGuiApplicationPrivate::processMouseEvent (e=0x525eab0) at kernel/qguiapplication.cpp:2282#24 0x00007f7564d1209c in QWindowSystemInterface::sendWindowSystemEvents (flags=...) at kernel/qwindowsysteminterface.cpp:1169#25 0x00007f755b361930 in ??? () at /lib/x86_64-linux-gnu/【libQt5WaylandClient.so.5】#26 0x00007f7565d47847 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#27 0x00007f7565d9f35f in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#28 0x00007f7565d46d7c in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#29 0x00007f756470a016 in QEventDispatcherGlib::processEvents (this=0x4879c20, flags=...) at kernel/qeventdispatcher_glib.cpp:423#30 0x00007f75646b0f6b in QEventLoop::exec (this=this@entry=0x7ffff9d39780, flags=..., flags@entry=...)at ../../include/QtCore/../../src/corelib/global/qflags.h:69---#0 QApplicationPrivate::notifyActiveWindowChange (this=0x48284f0, previous=0x5489c10) at kernel/qapplication.cpp:2098#1 0x00007f7564d3b275 in QGuiApplicationPrivate::processActivatedEvent (e=) at kernel/qguiapplication.cpp:2515#2 0x00007f7564d1209c in QWindowSystemInterface::sendWindowSystemEvents (flags=flags@entry=...) at kernel/qwindowsysteminterface.cpp:1169#3 0x00007f7564d12308 in QWindowSystemInterface::flushWindowSystemEvents (flags=...) at kernel/qwindowsysteminterface.cpp:1138#4 0x00007f75646de010 in QObject::event (this=0x50eb390, e=0x7f7524002310) at kernel/qobject.cpp:1347#5 0x00007f7565562ffe in QApplicationPrivate::notify_helper (this=, receiver=0x50eb390, e=0x7f7524002310)at kernel/qapplication.cpp:3645#6 0x00007f75646b24e8 in QCoreApplication::notifyInternal2 (receiver=0x50eb390, event=0x7f7524002310) at kernel/qcoreapplication.cpp:1064#7 0x00007f75646b26ae in QCoreApplication::sendEvent (receiver=, event=) at kernel/qcoreapplication.cpp:1462#8 0x00007f75646b5471 in QCoreApplicationPrivate::sendPostedEvents (receiver=0x0, event_type=0, data=0x4834be0)at kernel/qcoreapplication.cpp:1821#9 0x00007f75646b58f8 in QCoreApplication::sendPostedEvents (receiver=, event_type=)at kernel/qcoreapplication.cpp:1680#10 0x00007f756470a933 in postEventSourceDispatch (s=0x48386e0) at kernel/qeventdispatcher_glib.cpp:277#11 0x00007f7565d47847 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#12 0x00007f7565d9f35f in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#13 0x00007f7565d46d7c in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#14 0x00007f756470a016 in QEventDispatcherGlib::processEvents (this=0x4879c20, flags=...) at kernel/qeventdispatcher_glib.cpp:423#15 0x00007f75646b0f6b in QEventLoop::exec (this=this@entry=0x7ffff9d389c0, flags=..., flags@entry=...)at ../../include/QtCore/../../src/corelib/global/qflags.h:69#16 0x00007f75656e998f in QMenuPrivate::exec(QPoint const&, QAction*, std::function)(this=0x54fc510, p=..., action=0x0, positionFunction=...) at ../../include/QtCore/../../src/corelib/global/qflags.h:121#17 0x00007f75656e9aaf in QMenu::exec (this=, p=, action=) at widgets/qmenu.cpp:2710#18 0x0000000000483371 in ??? ()#19 0x00007f75646e978f in QtPrivate::QSlotObjectBase::call (a=0x7ffff9d38d30, r=0x4e422a0, this=0x4e7f0a0)at ../../include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398#20 doActivate (sender=0x4e422a0, signal_index=6, argv=0x7ffff9d38d30) at kernel/qobject.cpp:3925#21 0x00007f75646e2a7f in QMetaObject::activate(sender=sender@entry=0x4e422a0, m=m@entry=0x7f7565a7c0a0 , local_signal_index=local_signal_index@entry=3, argv=argv@entry=0x7ffff9d38d30) at kernel/qobject.cpp:3985#22 0x00007f756558a435 in QWidget::customContextMenuRequested (this=this@entry=0x4e422a0, _t1=...) at .moc/moc_qwidget.cpp:653#23 0x00007f75655a5dd3 in QWidget::event (this=this@entry=0x4e422a0, event=event@entry=0x7ffff9d39160) at kernel/qwidget.cpp:8856#24 0x00007f756565092e in QFrame::event (this=0x4e422a0, e=0x7ffff9d39160) at widgets/qframe.cpp:550#25 0x00007f75646b226b in QCoreApplicationPrivate::sendThroughObjectEventFilters(receiver=receiver@entry=0x4e6cf70, event=event@entry=0x7ffff9d39160) at kernel/qcoreapplication.cpp:1190#26 0x00007f7565562fee in QApplicationPrivate::notify_helper(this=this@entry=0x48284f0, receiver=receiver@entry=0x4e6cf70, e=e@entry=0x7ffff9d39160) at kernel/qapplication.cpp:3639#27 0x00007f756556a600 in QApplication::notify (this=, receiver=0x4e6cf70, e=) at kernel/qapplication.cpp:3251#28 0x00007f75646b24e8 in QCoreApplication::notifyInternal2 (receiver=0x4e6cf70, event=0x7ffff9d39160) at kernel/qcoreapplication.cpp:1064#29 0x00007f75646b2532 in QCoreApplication::forwardEvent (receiver=, event=, originatingEvent=)at kernel/qcoreapplication.cpp:1079#30 0x00007f75655bebc9 in QWidgetWindow::handleMouseEvent (this=this@entry=0x4f75e70, event=event@entry=0x7ffff9d39450)at kernel/qwidgetwindow.cpp:692
分析堆栈后的结论 :
执行openPopup接口后QWidgetList *QApplication::popupWidgets就会被赋值,不为nullptr
QApplicationPrivate::notifyActiveWindowChange接口中判断QWidgetList *QApplication::popupWidgets,如果不为nullptr,不会执行QApplication::setActiveWindow(这个接口的调用会激活窗口)
两个环境下QApplicationPrivate::notifyActiveWindowChange和QApplicationPrivate::openPopup的执行顺序有关系
xcb环境中先执行的 QApplicationPrivate::notifyActiveWindowChange 后执行 QApplicationPrivate::openPopup
wayland环境中先执行 QApplicationPrivate::openPopup 后执行 QApplicationPrivate::notifyActiveWindowChange
观察到堆栈中libQt5WaylandClient库没有符号信息,于是我下载源码进行编译,安装debug包,查看堆栈如下:
结果发现wayland环境下没有wayland库的堆栈信息了,似乎又和libglib库有关系了,之前的分析似乎又不对了
xcb #24 0x00007fa7a0f120e5 in QWindowSystemInterface::sendWindowSystemEvents (flags=..., flags@entry=...) at kernel/qwindowsysteminterface.cpp:1173#25 0x00007fa7976a77bf in xcbSourceDispatch (source=) at ./src/plugins/platforms/xcb/qxcbeventdispatcher.cpp:106#26 0x00007fa7a1f47847 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#27 0x00007fa7a1f9f35f in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#28 0x00007fa7a1f46d7c in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#29 0x00007fa7a090a016 in QEventDispatcherGlib::processEvents (this=0x6866850, flags=...) at kernel/qeventdispatcher_glib.cpp:423#30 0x00007fa7a08b0f6b in QEventLoop::exec (this=this@entry=0x7ffff641f230, flags=..., flags@entry=...) at ../../include/QtCore/../../src/corelib/global/qflags.h:69#31 0x00007fa7a08b90c6 in QCoreApplication::exec () at ../../include/QtCore/../../src/corelib/global/qflags.h:121#32 0x00000000004432da in main ()wayland #24 0x00007f7c7ef120e5 in QWindowSystemInterface::sendWindowSystemEvents (flags=...) at kernel/qwindowsysteminterface.cpp:1173#25 0x00007f7c77302930 in userEventSourceDispatch (source=) at ./src/platformsupport/eventdispatchers/qeventdispatcher_glib.cpp:74#26 0x00007f7c7ff47847 in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#27 0x00007f7c7ff9f35f in ??? () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#28 0x00007f7c7ff46d7c in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0#29 0x00007f7c7e90a016 in QEventDispatcherGlib::processEvents (this=0x5ab7440, flags=...) at kernel/qeventdispatcher_glib.cpp:423#30 0x00007f7c7e8b0f6b in QEventLoop::exec (this=this@entry=0x7ffcc299e2c0, flags=..., flags@entry=...) at ../../include/QtCore/../../src/corelib/global/qflags.h:69#31 0x00007f7c7e8b90c6 in QCoreApplication::exec () at ../../include/QtCore/../../src/corelib/global/qflags.h:121#32 0x00000000004432da in main ()
这里也许就和qtwayland那边没有什么关联了
修改方法
目前看,这个问题只能是修改qtbase源码,取消一些判断的逻辑
void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous){Q_UNUSED(previous);QWindow *wnd = QGuiApplicationPrivate::focus_window;//改成下面这段代码即可,后面我查了一下,qt6也已经这样修改了#ifndef Q_OS_MACOSif (inPopupMode()) {// some delayed focus event to ignore return;}#endifQWidget *tlw = qt_tlw_for_window(wnd);QApplication::setActiveWindow(tlw);// QTBUG-37126, Active X controls may set the focus on native child widgets.if (wnd && tlw && wnd != tlw->windowHandle()) {if (QWidgetWindow *widgetWindow = qobject_cast(wnd))if (QWidget *widget = widgetWindow->widget())if (widget->inherits("QAxHostWidget"))widget->setFocus(Qt::ActiveWindowFocusReason);}}