Internal tracking for quick effect item focus

focus used to be always forced to the root item of the view in the
"active screen" (which behavior is configurable between mouse poosition
and screen of active window)
now set focus to that particular view only if nothing is focused, also when
the user explicitly sets focus to an item in another view
remove focus to the old one so the item properly focused would be there

BUG:455807
BUG:455783
CCBUG:455633
This commit is contained in:
Marco Martin 2022-06-24 15:56:08 +00:00 committed by Nate Graham
parent aad0673961
commit 66d1278794
4 changed files with 47 additions and 4 deletions

View file

@ -435,6 +435,11 @@ QQuickItem *OffscreenQuickView::contentItem() const
return d->m_view->contentItem();
}
QQuickWindow *OffscreenQuickView::window() const
{
return d->m_view;
}
void OffscreenQuickView::setVisible(bool visible)
{
if (d->m_visible == visible) {

View file

@ -27,6 +27,7 @@ class QKeyEvent;
class QQmlContext;
class QQuickItem;
class QQuickWindow;
namespace KWin
{
@ -109,6 +110,7 @@ public:
/** The invisble root item of the window*/
QQuickItem *contentItem() const;
QQuickWindow *window() const;
/**
* @brief Marks the window as visible/invisible

View file

@ -10,6 +10,7 @@
#include <QQmlEngine>
#include <QQuickItem>
#include <QQuickWindow>
#include <QWindow>
namespace KWin
@ -220,6 +221,19 @@ QuickSceneView *QuickSceneEffect::viewAt(const QPoint &pos) const
return nullptr;
}
void QuickSceneEffect::activateView(QuickSceneView *view)
{
for (auto *otherView : d->views) {
if (otherView == view && !view->window()->activeFocusItem()) {
QFocusEvent focusEvent(QEvent::FocusIn, Qt::ActiveWindowFocusReason);
qApp->sendEvent(view->window(), &focusEvent);
} else if (otherView->window()->activeFocusItem()) {
QFocusEvent focusEvent(QEvent::FocusOut, Qt::ActiveWindowFocusReason);
qApp->sendEvent(otherView->window(), &focusEvent);
}
}
}
void QuickSceneEffect::paintScreen(int mask, const QRegion &region, ScreenPaintData &data)
{
Q_UNUSED(mask)
@ -288,6 +302,10 @@ void QuickSceneEffect::addScreen(EffectScreen *screen)
properties["width"] = view->geometry().width();
properties["height"] = view->geometry().height();
view->setRootItem(qobject_cast<QQuickItem *>(d->qmlComponent->createWithInitialProperties(properties)));
// we need the focus always set to the view of activescreen at first, and changed only upon user interaction
if (view->contentItem()) {
view->contentItem()->setFocus(false);
}
view->setAutomaticRepaint(false);
connect(view, &QuickSceneView::repaintNeeded, this, [view]() {
@ -400,16 +418,28 @@ void QuickSceneEffect::windowInputMouseEvent(QEvent *event)
}
if (target) {
if (buttons) {
activateView(target);
}
target->forwardMouseEvent(event);
}
}
void QuickSceneEffect::grabbedKeyboardEvent(QKeyEvent *keyEvent)
{
QuickSceneView *screenView = d->views.value(effects->activeScreen());
if (screenView) {
screenView->contentItem()->setFocus(true);
screenView->forwardKeyEvent(keyEvent);
auto it = std::find_if(d->views.constBegin(), d->views.constEnd(), [](QuickSceneView *v) {
return v->window()->activeFocusItem();
});
if (it == d->views.constEnd()) {
QuickSceneView *screenView = d->views.value(effects->activeScreen());
if (screenView) {
activateView(screenView);
screenView->forwardKeyEvent(keyEvent);
}
} else {
(*it)->forwardKeyEvent(keyEvent);
return;
}
}
@ -417,6 +447,7 @@ bool QuickSceneEffect::touchDown(qint32 id, const QPointF &pos, quint32 time)
{
for (QuickSceneView *screenView : qAsConst(d->views)) {
if (screenView->geometry().contains(pos.toPoint())) {
activateView(screenView);
return screenView->forwardTouchDown(id, pos, time);
}
}

View file

@ -92,6 +92,11 @@ public:
*/
QuickSceneView *viewAt(const QPoint &pos) const;
/**
* Sets the given @a view as active. It will get a focusin event and all the other views will be set as inactive
*/
void activateView(QuickSceneView *view);
/**
* Returns the source URL.
*/