Bug 500978 - Submenus open in standalone windows
Summary: Submenus open in standalone windows
Status: RESOLVED UPSTREAM
Alias: None
Product: kwin
Classification: Plasma
Component: wayland-generic (other bugs)
Version First Reported In: 6.3.2
Platform: Other Linux
: NOR normal
Target Milestone: ---
Assignee: KWin default assignee
URL:
Keywords: wayland-only
Depends on:
Blocks:
 
Reported: 2025-03-03 01:17 UTC by nilskemail+kde
Modified: 2025-06-02 16:21 UTC (History)
3 users (show)

See Also:
Latest Commit:
Version Fixed In:
Sentry Crash Report:


Attachments
Video showing the strange child menu behavior (2.10 MB, video/webm)
2025-03-03 01:19 UTC, nilskemail+kde
Details

Note You need to log in before you can comment on or make changes to this bug.
Description nilskemail+kde 2025-03-03 01:17:14 UTC
SUMMARY
When opening some of the children of the toolbars menus they sometimes seem to open in standalone windows with a window header (minimize, maximize, close)

STEPS TO REPRODUCE
1. Click on the toolbar item "View"
2. Move the cursor over some if the items which have child menus (i.e. those with a right chevron ">")

OBSERVED RESULT
The submenu sometimes opens in a standalone window

EXPECTED RESULT
The submenu should just be another layer in the main window

SOFTWARE/OS VERSIONS
Operating System: Fedora Linux 41
KDE Plasma Version: 6.3.2
KDE Frameworks Version: 6.11.0
Qt Version: 6.8.2
Kernel Version: 6.12.15-200.fc41.x86_64 (64-bit)
Graphics Platform: Wayland
Processors: 16 × AMD Ryzen 7 7840U w/ Radeon  780M Graphics
Memory: 30.6 GiB of RAM
Graphics Processor: AMD Radeon 780M
Comment 1 nilskemail+kde 2025-03-03 01:19:23 UTC
Created attachment 179053 [details]
Video showing the strange child menu behavior
Comment 2 Friedrich W. H. Kossebau 2025-03-03 13:44:12 UTC
Thanks for the report, the video shows the issue well.

Not something that can be fixed on Okteta side. On first thought this would be an issue of the window manager interacting with the widget toolkit on the menu window flags? So moving to kwin maintainers so they hopefully can find out if this is their side or perhaps upstream Qt5/Wayland issue...

KWin maintainers: please note Okteta is still Qt5 domain.
Comment 3 Zamundaaa 2025-03-03 16:41:46 UTC
One thing you can check is that the menu has the proper widget parent - if Qt can't figure out which (toplevel or popup) window the popups are supposed to attach to, it'll create a toplevel window instead of a popup.

Qt 6 has better heuristics for figuring out which window a popup was supposed to be attached to, but it's best if the problem is properly fixed on the application side.
Comment 4 nilskemail+kde 2025-03-03 18:00:30 UTC
Closer observation reveals that this happens exactly when one popup should be shown while another one is still open. If I always wait for the previous popup to disappear (e.g. by moving the mouse to an entry which does not have children) then this problem never appears. This can even be seen in the video
Comment 5 Friedrich W. H. Kossebau 2025-03-06 00:22:58 UTC
(In reply to Zamundaaa from comment #3)
> One thing you can check is that the menu has the proper widget parent 

This here is about menus part of the main menu bar menus tree. Those submenus are QMenus queried from QAction entries in QMenus plugged into QMenuBar.  I guess the popup is controlled by QMenu::internalDelayedPopup(), and there the menu widget relation internally seems to be trracked by "d->activeMenu->d_func()->causedPopup.widget = this;".

Many, if not all, of the submenus which seem affected by what people had observed are provided by KSelectAction. That one creates an internal QMenu instance, which it sets to itself via QAction::setMenu(). So there is no widget parent to this menu instance by default. And those QMenu instances will be accessed from QMenu containers which have those actions as entries, as by above referenced QMenu::internalDelayedPopup().
More precisely, the KSelectAction instances themselves are added to the QMainWindow's QMenuBar in one of the QMenu instances as created by KXmlGui's logic in Okteta's case. The KSelectionActions are owned by internal QObject instances, possibly not reachable from QMainWindow object child tree, so only lent into the menu's manifests.

I connected to the QMenu::aboutToShow signal, and parentWidget is a nullptr at the time.

KWin developers, would you know any data bits to set to help the heuristics you mentioned? 

Given the added observation "happens exactly when one popup should be shown while another one is still open" I suspect though perhaps some data lookup fails somewhere on the client or server side of the wayland protocols?
Comment 6 Vlad Zahorodnii 2025-05-27 11:25:45 UTC
(In reply to Friedrich W. H. Kossebau from comment #5)
> (In reply to Zamundaaa from comment #3)
> > One thing you can check is that the menu has the proper widget parent 
> 
> This here is about menus part of the main menu bar menus tree. Those
> submenus are QMenus queried from QAction entries in QMenus plugged into
> QMenuBar.  I guess the popup is controlled by QMenu::internalDelayedPopup(),
> and there the menu widget relation internally seems to be trracked by
> "d->activeMenu->d_func()->causedPopup.widget = this;".
> 
> Many, if not all, of the submenus which seem affected by what people had
> observed are provided by KSelectAction. That one creates an internal QMenu
> instance, which it sets to itself via QAction::setMenu(). So there is no
> widget parent to this menu instance by default. And those QMenu instances
> will be accessed from QMenu containers which have those actions as entries,
> as by above referenced QMenu::internalDelayedPopup().
> More precisely, the KSelectAction instances themselves are added to the
> QMainWindow's QMenuBar in one of the QMenu instances as created by KXmlGui's
> logic in Okteta's case. The KSelectionActions are owned by internal QObject
> instances, possibly not reachable from QMainWindow object child tree, so
> only lent into the menu's manifests.
> 
> I connected to the QMenu::aboutToShow signal, and parentWidget is a nullptr
> at the time.
> 
> KWin developers, would you know any data bits to set to help the heuristics
> you mentioned? 
> 
> Given the added observation "happens exactly when one popup should be shown
> while another one is still open" I suspect though perhaps some data lookup
> fails somewhere on the client or server side of the wayland protocols?

On the compositor side, there's nothing that we can do. It's Qt that decides whether to put a decoration. We have to look into fixing the client side, unfortunately. For example, by setting proper transient parent hints, or making sure that the right transient parent can be found. Do you know if this happens with Qt 6? Is there any chance of making a demo app that can trigger this bug?
Comment 7 Vlad Zahorodnii 2025-05-27 11:26:32 UTC
> Is there any chance of making a demo app that can trigger this bug?

(that can be built both against Qt 5 and Qt 6)
Comment 8 David Edmundson 2025-05-27 11:45:03 UTC
This should not happen from Qt6.9.1 onwards
Comment 9 Bug Janitor Service 2025-06-02 11:51:11 UTC
A possibly relevant merge request was started @ https://invent.kde.org/frameworks/kxmlgui/-/merge_requests/284
Comment 10 Christoph Cullmann 2025-06-02 16:21:06 UTC
Git commit 70c702536ab24f15d36c8fd6003de866290ed8fe by Christoph Cullmann, on behalf of Vlad Zahorodnii.
Committed on 02/06/2025 at 16:10.
Pushed by cullmann into branch 'master'.

Fix popup transient parents

Currently, the KXMLGUIBuilder forces the QMainWindow as the transient
parent for QMenu objects. The age of this code is more than 20 years.

In Qt 6, a normal QWidget can be a parent of a QMenu. In that case, the
QMenu will walk the widget tree and use the nearest widget with a
native window as the transient parent.

This change relaxes the restrictions in the KXMLGUIBuilder, so the
QMenu can do the right thing for us. Note that a menu can be the
toplevel element. In that case, the container widget is used as the
transient parent.

Co-authored-by: Christoph Cullmann <christoph@cullmann.dev>

M  +4    -15   src/kxmlguibuilder.cpp

https://invent.kde.org/frameworks/kxmlgui/-/commit/70c702536ab24f15d36c8fd6003de866290ed8fe