diff options
author | Paul Olav Tvete <paul.tvete@qt.io> | 2021-11-29 17:23:18 +0100 |
---|---|---|
committer | Paul Olav Tvete <paul.tvete@qt.io> | 2021-12-07 02:40:56 +0100 |
commit | 8c0b1e06d9679676d12ff92db981198077eeda76 (patch) | |
tree | d908b91d72bded41cdbfce88cd6d099d48da898a /src/quickwidgets/qquickwidget.cpp | |
parent | 61e325460ce810b645fc3595ae38a86468c289a3 (diff) |
Fix focus for items inside a QQuickWidget in a QGraphicsProxyWidget
QQuickWidgetRenderControl::renderWindowFor() did not take the proxy
widget into account, making it impossible to give focus to items
inside a QGraphicsProxyWidget by clicking on the item.
This patch is based on a patch by Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>,
which fixed renderWindowFor(), but did not handle the case where a proxy widget
was in multiple views.
This version of the patch adds QQuickRenderControlPrivate::isRenderWindowFor(),
which allows all the views of the proxy widget to handle focus.
This patch also carefully preserves the non-obvious feature of the
previous implementation where all windows are considered to have focus
if QGuiApplication::focusWindow() == nullptr.
[ChangeLog][QuickWidget][Quick items inside a QuickWidget that is inside a
QGraphicsProxyWidget can now get focus by clicking.]
Fixes: QTBUG-91479
Pick-to: 6.2
Change-Id: I4a6fbbbeda2d14b5a6d8eb8218d5b14a3404d9c3
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/quickwidgets/qquickwidget.cpp')
-rw-r--r-- | src/quickwidgets/qquickwidget.cpp | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index d0cc6f9048..37b3823bde 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -83,6 +83,11 @@ #include <QtQuick/qquickgraphicsdevice.h> #include <QtQuick/qquickrendertarget.h> +#include "private/qwidget_p.h" + +#include <QtWidgets/qgraphicsscene.h> +#include <QtWidgets/qgraphicsview.h> + QT_BEGIN_NAMESPACE QQuickWidgetOffscreenWindow::QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control) @@ -104,19 +109,80 @@ public: } }; +class QQuickWidgetRenderControlPrivate; + class QQuickWidgetRenderControl : public QQuickRenderControl { + Q_DECLARE_PRIVATE(QQuickWidgetRenderControl) +public: + QQuickWidgetRenderControl(QQuickWidget *quickwidget); + QWindow *renderWindow(QPoint *offset) override; + +}; + +class QQuickWidgetRenderControlPrivate : public QQuickRenderControlPrivate +{ public: - QQuickWidgetRenderControl(QQuickWidget *quickwidget) : m_quickWidget(quickwidget) {} - QWindow *renderWindow(QPoint *offset) override { - if (offset) - *offset = m_quickWidget->mapTo(m_quickWidget->window(), QPoint()); - return m_quickWidget->window()->windowHandle(); + Q_DECLARE_PUBLIC(QQuickWidgetRenderControl) + QQuickWidgetRenderControlPrivate(QQuickWidgetRenderControl *renderControl, QQuickWidget *qqw) + : QQuickRenderControlPrivate(renderControl) + , m_quickWidget(qqw) + { + } + + bool isRenderWindow(const QWindow *w) override { +#if QT_CONFIG(graphicsview) + QWidgetPrivate *widgetd = QWidgetPrivate::get(m_quickWidget); + auto *proxy = (widgetd && widgetd->extra) ? widgetd->extra->proxyWidget : nullptr; + auto *scene = proxy ? proxy->scene() : nullptr; + if (scene) { + for (const auto &view : scene->views()) { + if (view->window()->windowHandle() == w) + return true; + } + } + + return m_quickWidget->window()->windowHandle() == w; +#endif } -private: QQuickWidget *m_quickWidget; }; +QQuickWidgetRenderControl::QQuickWidgetRenderControl(QQuickWidget *quickWidget) + : QQuickRenderControl(*(new QQuickWidgetRenderControlPrivate(this, quickWidget)), nullptr) +{ +} + +QWindow *QQuickWidgetRenderControl::renderWindow(QPoint *offset) +{ + Q_D(QQuickWidgetRenderControl); + if (offset) + *offset = d->m_quickWidget->mapTo(d->m_quickWidget->window(), QPoint()); + + QWindow *result = nullptr; +#if QT_CONFIG(graphicsview) + QWidgetPrivate *widgetd = QWidgetPrivate::get(d->m_quickWidget); + if (widgetd->extra) { + if (auto proxy = widgetd->extra->proxyWidget) { + auto scene = proxy->scene(); + if (scene) { + const auto views = scene->views(); + if (!views.isEmpty()) { + // Get the first QGV containing the proxy. Not ideal, but the callers + // of this function aren't prepared to handle more than one render window. + auto candidateView = views.first(); + result = candidateView->window()->windowHandle(); + } + } + } + } +#endif + if (!result) + result = d->m_quickWidget->window()->windowHandle(); + + return result; +} + void QQuickWidgetPrivate::initOffscreenWindow() { Q_Q(QQuickWidget); |