Bug 445277

Summary: f8e14f9c Breaks KeyEvent emitting
Product: [Frameworks and Libraries] frameworks-kirigami Reporter: Oleg Solovyov <mcpain>
Component: generalAssignee: Marco Martin <notmart>
Status: RESOLVED FIXED    
Severity: normal CC: darktemplar, jbb, kde, kde, nate
Priority: VHI Keywords: regression
Version: 5.86.0   
Target Milestone: Not decided   
Platform: Other   
OS: Linux   
Latest Commit: Version Fixed In: 5.89
Sentry Crash Report:
Bug Depends on:    
Bug Blocks: 442079    
Attachments: test app
full backtrace for setKeyboardGrabEnabled.txt
more backtraces.txt

Description Oleg Solovyov 2021-11-10 12:51:14 UTC
STEPS TO REPRODUCE
0. Initial condition: have an activity with Alt+B shortcut for switching 
1. Open activity settings (any activity, either same or different one)
2. Set shortcut to Alt+B

OBSERVED RESULT
Widget acts like "B" is never pressed

EXPECTED RESULT
"Alt+B..." is shown

ADDITIONAL INFORMATION
Broken after commit
* f8e14f9c Rewrite Units in c++
Comment 1 Oleg Solovyov 2021-11-10 12:53:03 UTC
Debugger gave info that KeySequenceRecorderPrivate::eventFilter for key "B" is not even called after pressing "Alt" modifier.

event for "B" alone is processed successfully
Comment 2 Oleg Solovyov 2021-11-11 15:46:53 UTC
Investigated up to QXcbKeyboard::handleKeyPressEvent

seems like KeyPress event for "B" is missing, KeyRelease is there.
Comment 3 Nate Graham 2021-11-12 22:38:43 UTC
CCing Jonah who authored that commit.
Comment 4 Oleg Solovyov 2021-11-15 08:26:02 UTC
Found that backtraces are different (e.g. when pressing F w/o modifiers)

https://pastebin.com/mJqG5X0Z

Perhaps Alt+F event is grabbed and caught somewhere else (could be QWidgetWindow::event or QWidget::event)
Comment 5 Oleg Solovyov 2021-11-16 13:26:21 UTC
Created attachment 143623 [details]
test app

Invoking manually via D-Bus affects nothing

Re-implementing manually fixes this bug.
Comment 6 Oleg Solovyov 2021-11-17 14:39:26 UTC
There are different types of widget where KeyEvents are inhibited: QWidgetWindow vs. QQuickWindow

broken:
#0  QQuickWindow::QQuickWindow (this=0x555557767c80, dd=..., control=0x555557538140) at items/qquickwindow.cpp:1504
#1  0x00007fff997a5b54 in QQuickWidgetPrivate::init (this=0x55555715de20, e=0x0) at qquickwidget.cpp:108
#2  0x00007fff997d0cd2 in Dialog::Private::createTab (file=..., title=..., this=0x7fffec012f30) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/dialog.cpp:66
#3  Dialog::Dialog (parent=0x0, this=0x555555b344b0) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/dialog.cpp:146
#4  Dialog::showDialog (id=...) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/dialog.cpp:121
#5  0x00007fff997d15e0 in ActivitySettings::configureActivity (this=0x555555942690, id=...) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/activitysettings.cpp:35

fine:
#0  QWidgetWindow::QWidgetWindow (this=0x55555779a820, widget=0x555555ad69c0) at kernel/qwidgetwindow.cpp:159
#1  0x00007ffff6a9e942 in QWidgetPrivate::createTLSysExtra (this=this@entry=0x7fffb0030c70) at kernel/qwidget.cpp:1369
#2  0x00007ffff6a9f1f8 in QWidgetPrivate::create (this=this@entry=0x7fffb0030c70) at kernel/qwidget.cpp:1252
#3  0x00007ffff6a9f336 in QWidget::create (this=0x555555ad69c0, window=<optimized out>, initializeWindow=<optimized out>, destroyOldWindow=<optimized out>) at kernel/qwidget.cpp:1179
#4  0x00007ffff6aac5ca in QWidgetPrivate::setVisible (this=0x7fffb0030c70, visible=<optimized out>) at kernel/qwidget.cpp:8063
#5  0x00007ffff6aac9c2 in QWidget::setVisible (this=this@entry=0x555555ad69c0, visible=visible@entry=true) at kernel/qwidget.cpp:8044
#6  0x00007ffff6c76614 in QDialog::setVisible (this=0x555555ad69c0, visible=<optimized out>) at dialogs/qdialog.cpp:787
#7  0x00007fff997d35e0 in ActivitySettings::configureActivity (this=0x555555845260, id=...) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/activitysettings.cpp:35
Comment 7 Oleg Solovyov 2021-11-18 06:48:10 UTC
Clean BTs w/o optimization in Qt and static functions

broken:
#0  QQuickWindow::QQuickWindow (this=0x55555686cc30, dd=..., control=0x55555709d3f0) at items/qquickwindow.cpp:1504
#1  0x00007fff94feeb54 in QQuickWidgetPrivate::init (this=0x5555572083a0, e=0x0) at qquickwidget.cpp:108
#2  0x00007fff95018d26 in Dialog::Private::createTab (file=..., title=..., this=0x7fffec00eee0) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/dialog.cpp:66
#3  Dialog::Dialog (this=0x55555652b480, parent=0x0) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/dialog.cpp:132
#4  0x00007fff9501a5df in ActivitySettings::configureActivity (this=<optimized out>, id=...) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/activitysettings.cpp:37

fine:
#0  QWidgetWindow::QWidgetWindow (this=0x5555579b7a80, widget=0x555557853dd0) at kernel/qwidgetwindow.cpp:159
#1  0x00007ffff68a1ea0 in QWidgetPrivate::createTLSysExtra (this=0x55555783bc40) at kernel/qwidget.cpp:1369
#2  0x00007ffff68a15f5 in QWidgetPrivate::create (this=0x55555783bc40) at kernel/qwidget.cpp:1252
#3  0x00007ffff68a1100 in QWidget::create (this=0x555557853dd0, window=0, initializeWindow=true, destroyOldWindow=true) at kernel/qwidget.cpp:1179
#4  0x00007ffff68b659b in QWidgetPrivate::setVisible (this=0x55555783bc40, visible=true) at kernel/qwidget.cpp:8063
#5  0x00007ffff68b6452 in QWidget::setVisible (this=0x555557853dd0, visible=true) at kernel/qwidget.cpp:8044
#6  0x00007ffff6b179d6 in QDialog::setVisible (this=0x555557853dd0, visible=true) at dialogs/qdialog.cpp:787
#7  0x00007ffff68b5247 in QWidget::show (this=0x555557853dd0) at kernel/qwidget.cpp:7670
#8  0x00007fff950c65f2 in ActivitySettings::configureActivity (this=<optimized out>, id=...) at /usr/src/debug/plasma-desktop-5.23.3/kcms/activities/imports/activitysettings.cpp:39
Comment 8 darktemplar 2021-11-18 15:27:31 UTC
Created attachment 143697 [details]
full backtrace for setKeyboardGrabEnabled.txt

It looks like platformWindow is missing with new kirigami when QWindow::setKeyboardGrabEnabled is called. Here's old kirigami:

(gdb) print d->platformWindow
$3 = (QPlatformWindow *) 0x55879d8b6370
(gdb) print *d->platformWindow
$4 = {<QPlatformSurface> = {_vptr.QPlatformSurface = 0x7f2d69594ab0 <vtable for QXcbGlxWindow+440>, m_surface = 0x55879d9cdab0}, d_ptr = {d = 0x55879d8c0c10}}

Here's new kirigami:

(gdb) print d->platformWindow
$10 = (QPlatformWindow *) 0x0

Code in question:
https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/kernel/qwindow.cpp?h=v5.15.2#n2044

It looks like offscreen window without platform window is created and used, and it's unable to grab keyboard:

https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quickwidgets/qquickwidget.cpp?h=v5.15.2#n103

Full backtrace for QWindow::setKeyboardGrabEnabled call is in attachment.
Comment 9 darktemplar 2021-11-19 10:58:10 UTC
Created attachment 143724 [details]
more backtraces.txt

With kirigami 5.86.0 1 instance of QQuickWindow and 2 instances of QWidgetWindow are created, KeySequenceRecorder is created once for QQuickWindow, an offscreen rendering window, it doesn't have platform window and that's it. With kirigami 5.85.0 1 instance of QQuickWindow and 2 instances of QWidgetWindow are created as well, KeySequenceRecorder is created for QQuickWindow, an offscreen rendering window, then during QQmlEngine::retranslate it's recreated for QWidgetWindow, which has platform window, and it works fine. I'm not sure if KeySequenceRecorder was recreated accidentally, but now when it is not recreated, this issue appears. More backtraces are in attachment.
Comment 10 Oleg Solovyov 2021-11-22 12:10:20 UTC
Workaround in activity settings: https://invent.kde.org/plasma/plasma-desktop/-/merge_requests/712
Comment 11 Oleg Solovyov 2021-11-22 12:37:07 UTC
Unless this bug is fixed, multi-shortcuts implementation are useless.
Comment 12 David Redondo 2021-11-22 12:59:34 UTC
Since we render in a offscreenwindow, the recorder should be on the renderwindow see https://invent.kde.org/frameworks/kdeclarative/-/blob/master/src/qmlcontrols/kquickcontrols/KeySequenceItem.qml#L45, which is wrapper for https://doc.qt.io/qt-5/qquickrendercontrol.html#renderWindowFor

Theory: Due to side effects from before/after the kirigami change,  the renderwindow is not set yet when the binding is evaluated

lazy fix would be set that more often (before starting recording)
Comment 13 Bug Janitor Service 2021-11-22 13:24:13 UTC
A possibly relevant merge request was started @ https://invent.kde.org/frameworks/kdeclarative/-/merge_requests/93
Comment 14 David Redondo 2021-11-22 13:24:50 UTC
Thanks for the investigation here, which helped to have this theory quite quickly
Comment 15 David Redondo 2021-11-25 14:38:25 UTC
Git commit 2caa62d11f322ca5c9829b6bc91839e8afd42686 by David Redondo.
Committed on 25/11/2021 at 14:37.
Pushed by davidre into branch 'master'.

KeySequenceItem: Make sure we record on the correct window

Unfortunately renderWindowFor is just a simple function call and
so the binding is not updated when it would change. Now we make sure
to update the window before each recording.

M  +1    -1    src/qmlcontrols/kquickcontrols/KeySequenceItem.qml

https://invent.kde.org/frameworks/kdeclarative/commit/2caa62d11f322ca5c9829b6bc91839e8afd42686