Skip to content

Commit 4cd53e2

Browse files
tcl3awesomekling
authored andcommitted
UI/Qt: Forward native window container focus events to the host
The view's Vulkan window container becomes its focus proxy while visible. showing it moves keyboard focus onto the container and the view reports a focus loss to WebContent. On Wayland, the embedded window never receives keyboard focus, meaning focus was never reported back, so the text caret stopped appearing in editable content.
1 parent e4ae86b commit 4cd53e2

4 files changed

Lines changed: 75 additions & 0 deletions

File tree

Tests/UI/Qt/TestNativeWindowContainerFocus.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ struct TestWindow {
4646
QWidget& sibling;
4747
};
4848

49+
class FocusEventRecorder final : public QObject {
50+
public:
51+
QEvent::Type last_focus_event { QEvent::None };
52+
53+
private:
54+
virtual bool eventFilter(QObject*, QEvent* event) override
55+
{
56+
if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut)
57+
last_focus_event = event->type();
58+
return false;
59+
}
60+
};
61+
4962
}
5063

5164
TEST_CASE(focus_proxy_follows_container_visibility)
@@ -98,6 +111,33 @@ TEST_CASE(focus_is_not_stolen_from_other_widgets)
98111
EXPECT_EQ(QApplication::focusWidget(), &widgets.sibling);
99112
}
100113

114+
TEST_CASE(container_focus_events_are_forwarded_to_the_host)
115+
{
116+
application();
117+
TestWindow widgets;
118+
Ladybird::install_native_window_container_focus_forwarding(widgets.host, widgets.container);
119+
120+
FocusEventRecorder recorder;
121+
widgets.host.installEventFilter(&recorder);
122+
123+
widgets.host.setFocus();
124+
QApplication::processEvents();
125+
126+
Ladybird::set_native_window_container_visible(widgets.host, widgets.container, true);
127+
EXPECT_EQ(QApplication::focusWidget(), &widgets.container);
128+
EXPECT_EQ(recorder.last_focus_event, QEvent::FocusIn);
129+
130+
widgets.sibling.setFocus();
131+
EXPECT_EQ(recorder.last_focus_event, QEvent::FocusOut);
132+
133+
widgets.container.setFocus();
134+
EXPECT_EQ(recorder.last_focus_event, QEvent::FocusIn);
135+
136+
Ladybird::set_native_window_container_visible(widgets.host, widgets.container, false);
137+
EXPECT_EQ(QApplication::focusWidget(), &widgets.host);
138+
EXPECT_EQ(recorder.last_focus_event, QEvent::FocusIn);
139+
}
140+
101141
TEST_CASE(visibility_changes_are_idempotent)
102142
{
103143
application();

UI/Qt/NativeWindowContainer.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,37 @@
66

77
#include <UI/Qt/NativeWindowContainer.h>
88

9+
#include <QCoreApplication>
10+
#include <QFocusEvent>
911
#include <QWidget>
1012

1113
namespace Ladybird {
1214

15+
namespace {
16+
17+
class FocusEventForwarder final : public QObject {
18+
public:
19+
FocusEventForwarder(QWidget& host, QWidget& container)
20+
: QObject(&container)
21+
, m_host(host)
22+
{
23+
}
24+
25+
private:
26+
virtual bool eventFilter(QObject*, QEvent* event) override
27+
{
28+
if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) {
29+
QFocusEvent forwarded_event { event->type(), static_cast<QFocusEvent*>(event)->reason() };
30+
QCoreApplication::sendEvent(&m_host, &forwarded_event);
31+
}
32+
return false;
33+
}
34+
35+
QWidget& m_host;
36+
};
37+
38+
}
39+
1340
void set_native_window_container_visible(QWidget& host, QWidget& container, bool visible)
1441
{
1542
if (container.isVisible() == visible)
@@ -31,4 +58,9 @@ void set_native_window_container_visible(QWidget& host, QWidget& container, bool
3158
}
3259
}
3360

61+
void install_native_window_container_focus_forwarding(QWidget& host, QWidget& container)
62+
{
63+
container.installEventFilter(new FocusEventForwarder(host, container));
64+
}
65+
3466
}

UI/Qt/NativeWindowContainer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ namespace Ladybird {
1414
// consistent: The container is the host's focus proxy only while it's visible.
1515
void set_native_window_container_visible(QWidget& host, QWidget& container, bool visible);
1616

17+
void install_native_window_container_focus_forwarding(QWidget& host, QWidget& container);
18+
1719
}

UI/Qt/WebContentViewLinux.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,7 @@ void WebContentView::create_vulkan_window()
906906
m_vulkan_window_container->setMouseTracking(true);
907907
m_vulkan_window_container->setGeometry(rect());
908908
m_vulkan_window_container->hide();
909+
install_native_window_container_focus_forwarding(*this, *m_vulkan_window_container);
909910
}
910911

911912
void WebContentView::set_vulkan_window_container_visible(bool visible)

0 commit comments

Comments
 (0)