[vlc-commits] [Git][videolan/vlc][master] 7 commits: configure: check for qt private header availability

Steve Lhomme (@robUx4) gitlab at videolan.org
Fri Mar 10 10:05:59 UTC 2023



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
4ce5e03e by Pierre Lamot at 2023-03-10T08:38:25+00:00
configure: check for qt private header availability

- - - - -
fe6d64d3 by Pierre Lamot at 2023-03-10T08:38:25+00:00
meson: check for qt private header availability

- - - - -
231e1709 by Pierre Lamot at 2023-03-10T08:38:25+00:00
contrib: patch qtdeclarative for accessibility

This allows quick items to report accessibility events to the right window when
doing off-screen rendering

see QTBUG-67290 and https://codereview.qt-project.org/c/qt/qtdeclarative/+/348284

Qt5 version of the patch is cherry-picked from kde patchset from
https://invent.kde.org/qt/qt/qtdeclarative/
(6d1dd8925f160d6ad02ea646eac638675bdf9f1c)

first patch is mainly here in order to be able to apply second patch correctly
as we don't use the actual QQuickWidget in our code

- - - - -
c71f0c08 by Pierre Lamot at 2023-03-10T08:38:25+00:00
qt: add base window classes for compositors

CompositorOffscreenWindow allows to fake making the window visible without
instantiating it

DummyRenderWindow is a simple window that doesn't draw anything, as using a bare
QWindow on Linux makes the window freeze while resizing

- - - - -
8e725d6e by Pierre Lamot at 2023-03-10T08:38:25+00:00
qt: fix accessiblity with DirectComposition compositor

The method is basically the same as commit
41926e08d73ea6c4bbfc87a1dd52d2cdbc435c27 from QtDeclarative but applied to our
composition architecture

in a nutshell

- the offscreen QQuickWindow must not report the child interfaces
- the render QWindow must report the child interfaces
- The child interfaces must report the render window as the parent

We implement QAccessibleObject for both window implementing theses policies.

Focus events are forwarded to the right window (from qml to the render
window and vice-versa).

We also need to fake the visibility of the offscreen window to make it behave as
visible without creating an actual window

- - - - -
e854adcf by Pierre Lamot at 2023-03-10T08:38:25+00:00
qt: switch the render window from a QMainWindow (QWidget) to a QWindow

QMainWindow is based on QWidget but we don't need the associated features, and
it comes with its own QWindow and we have no control over it.

- - - - -
9d8fa318 by Pierre Lamot at 2023-03-10T08:38:25+00:00
qt: fix accessiblity with X11 compositor

this follows the same scheme as DComp compositor

- - - - -


21 changed files:

- configure.ac
- + contrib/src/qtdeclarative/0001-Make-sure-QQuickWidget-and-its-offscreen-window-s-sc.patch
- + contrib/src/qtdeclarative/0002-Implement-accessibility-for-QQuickWidget.patch
- contrib/src/qtdeclarative/rules.mak
- modules/gui/qt/Makefile.am
- modules/gui/qt/maininterface/compositor.hpp
- + modules/gui/qt/maininterface/compositor_accessibility.cpp
- + modules/gui/qt/maininterface/compositor_accessibility.hpp
- + modules/gui/qt/maininterface/compositor_common.cpp
- + modules/gui/qt/maininterface/compositor_common.hpp
- modules/gui/qt/maininterface/compositor_dcomp.cpp
- modules/gui/qt/maininterface/compositor_dcomp.hpp
- modules/gui/qt/maininterface/compositor_dcomp_uisurface.cpp
- modules/gui/qt/maininterface/compositor_dcomp_uisurface.hpp
- modules/gui/qt/maininterface/compositor_x11.cpp
- modules/gui/qt/maininterface/compositor_x11.hpp
- modules/gui/qt/maininterface/compositor_x11_renderwindow.cpp
- modules/gui/qt/maininterface/compositor_x11_renderwindow.hpp
- modules/gui/qt/maininterface/compositor_x11_uisurface.cpp
- modules/gui/qt/maininterface/compositor_x11_uisurface.hpp
- modules/gui/qt/meson.build


Changes:

=====================================
configure.ac
=====================================
@@ -3971,6 +3971,7 @@ AS_IF([test "${enable_qt}" != "no"], [
 
       QT_PATH="$(eval $PKG_CONFIG --variable=exec_prefix Qt5Core)"
       QT_HOST_PATH="$(eval $PKG_CONFIG --variable=host_bins Qt5Core)"
+      QT_INCLUDE_DIRECTORY="$(eval $PKG_CONFIG --variable=includedir Qt5Core)"
       QT_VERSION="$(eval $PKG_CONFIG --modversion Qt5Gui)"
       AC_PATH_PROGS(MOC, [moc-qt5 moc], moc, ["${QT_HOST_PATH}" "${QT_PATH}/bin"])
       AC_PATH_PROGS(RCC, [rcc-qt5 rcc], rcc, ["${QT_HOST_PATH}" "${QT_PATH}/bin"])
@@ -3980,6 +3981,28 @@ AS_IF([test "${enable_qt}" != "no"], [
           AC_MSG_WARN([qmlcachegen not found])
       ])
 
+      dnl Check private headers avaibility
+      VLC_SAVE_FLAGS
+      CPPFLAGS="${CPPFLAGS} ${QT_CFLAGS}"
+      CPPFLAGS="${CPPFLAGS} -I${QT_INCLUDE_DIRECTORY}/QtCore/${QT_VERSION}"
+      CPPFLAGS="${CPPFLAGS} -I${QT_INCLUDE_DIRECTORY}/QtCore/${QT_VERSION}/QtCore"
+      CPPFLAGS="${CPPFLAGS} -I${QT_INCLUDE_DIRECTORY}/QtGui/${QT_VERSION}"
+      CPPFLAGS="${CPPFLAGS} -I${QT_INCLUDE_DIRECTORY}/QtGui/${QT_VERSION}/QtGui"
+      CPPFLAGS="${CPPFLAGS} -I${QT_INCLUDE_DIRECTORY}/QtQml/${QT_VERSION}"
+      CPPFLAGS="${CPPFLAGS} -I${QT_INCLUDE_DIRECTORY}/QtQml/${QT_VERSION}/QtQml"
+      CPPFLAGS="${CPPFLAGS} -I${QT_INCLUDE_DIRECTORY}/QtQuick/${QT_VERSION}"
+      CPPFLAGS="${CPPFLAGS} -I${QT_INCLUDE_DIRECTORY}/QtQuick/${QT_VERSION}/QtQuick"
+
+      AS_IF([test "${SYS}" != "mingw32"], [
+          CPPFLAGS="${CPPFLAGS} -fPIC"
+      ])
+
+      AC_LANG_PUSH([C++])
+      AC_CHECK_HEADERS([private/qquickitem_p.h private/qquickwindow_p.h],
+         [have_declarative_private="yes"], [])
+      AC_LANG_POP([C++])
+      VLC_RESTORE_FLAGS
+
       VLC_SAVE_FLAGS
       CPPFLAGS="${CPPFLAGS} ${QT_CFLAGS}"
       AC_COMPILE_IFELSE(
@@ -4044,10 +4067,12 @@ AS_IF([test "${enable_qt}" != "no"], [
   ALIASES="${ALIASES} qvlc"
 ])
 AC_SUBST([QT_VERSION])
+AC_SUBST([QT_INCLUDE_DIRECTORY])
 AM_CONDITIONAL([ENABLE_QT], [test "$enable_qt" != "no"])
 AM_CONDITIONAL([HAVE_QT5_X11], [test "${have_qt5_x11}" = "yes"])
 AM_CONDITIONAL([HAVE_QT5_WAYLAND], [test "${have_qt5_wayland}" = "yes"])
 AM_CONDITIONAL([HAVE_QT5_GTK], [test "${have_qt5_gtk}" = "yes"])
+AM_CONDITIONAL([HAVE_QT5_DECLARATIVE_PRIVATE], [test "${have_declarative_private}" = "yes"])
 
 dnl
 dnl detect kde4-config patch (used for kde solids).


=====================================
contrib/src/qtdeclarative/0001-Make-sure-QQuickWidget-and-its-offscreen-window-s-sc.patch
=====================================
@@ -0,0 +1,84 @@
+From 3bb63935369d7e1baf53aa401563cc75b87397fb Mon Sep 17 00:00:00 2001
+From: Vlad Zahorodnii <vlad.zahorodnii at kde.org>
+Date: Sat, 29 Jan 2022 21:59:33 +0200
+Subject: [PATCH 1/2] Make sure QQuickWidget and its offscreen window's screens
+ are always in sync
+
+By default, the offscreen window is placed on the primary screen.
+However, if the parent widget argument is passed to the QQuickWidget's
+constructor, then QQuickWidget's and the offscreen window's screens can
+be different and that can create rendering issues, e.g. blurry text if
+the primary screen and QQuickWidget's screen have different scale
+factors.
+
+Change-Id: I10c62b5635664f943b11828773f14017f198a770
+Reviewed-by: David Edmundson <davidedmundson at kde.org>
+Reviewed-by: Laszlo Agocs <laszlo.agocs at qt.io>
+(cherry picked from commit a2a2734bffa1459639b31fb3f4f83873ba44ab5c)
+---
+ src/quickwidgets/qquickwidget.cpp | 26 +++++++++++---------------
+ 1 file changed, 11 insertions(+), 15 deletions(-)
+
+diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
+index 39780f8de3..223d91f579 100644
+--- a/src/quickwidgets/qquickwidget.cpp
++++ b/src/quickwidgets/qquickwidget.cpp
+@@ -106,6 +106,7 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
+ 
+     renderControl = new QQuickWidgetRenderControl(q);
+     offscreenWindow = new QQuickWindow(*new QQuickOffcreenWindowPrivate(),renderControl);
++    offscreenWindow->setScreen(q->screen());
+     offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
+     offscreenWindow->setObjectName(QString::fromLatin1("QQuickOffScreenWindow"));
+     // Do not call create() on offscreenWindow.
+@@ -901,9 +902,7 @@ void QQuickWidgetPrivate::createContext()
+ 
+         context = new QOpenGLContext;
+         context->setFormat(offscreenWindow->requestedFormat());
+-        const QWindow *win = q->window()->windowHandle();
+-        if (win && win->screen())
+-            context->setScreen(win->screen());
++        context->setScreen(q->screen());
+         QOpenGLContext *shareContext = qt_gl_global_share_context();
+         if (!shareContext)
+             shareContext = QWidgetPrivate::get(q->window())->shareContext();
+@@ -1520,19 +1519,16 @@ bool QQuickWidget::event(QEvent *e)
+         d->handleWindowChange();
+         break;
+ 
+-    case QEvent::ScreenChangeInternal:
+-        if (QWindow *window = this->window()->windowHandle()) {
+-            QScreen *newScreen = window->screen();
+-
+-            if (d->offscreenWindow)
+-                d->offscreenWindow->setScreen(newScreen);
+-            if (d->offscreenSurface)
+-                d->offscreenSurface->setScreen(newScreen);
++    case QEvent::ScreenChangeInternal: {
++        QScreen *newScreen = screen();
++        if (d->offscreenWindow)
++            d->offscreenWindow->setScreen(newScreen);
++        if (d->offscreenSurface)
++            d->offscreenSurface->setScreen(newScreen);
+ #if QT_CONFIG(opengl)
+-            if (d->context)
+-                d->context->setScreen(newScreen);
++        if (d->context)
++            d->context->setScreen(newScreen);
+ #endif
+-        }
+ 
+         if (d->useSoftwareRenderer
+ #if QT_CONFIG(opengl)
+@@ -1545,7 +1541,7 @@ bool QQuickWidget::event(QEvent *e)
+             d->render(true);
+         }
+         break;
+-
++    }
+     case QEvent::Show:
+     case QEvent::Move:
+         d->updatePosition();
+-- 
+2.34.1
+


=====================================
contrib/src/qtdeclarative/0002-Implement-accessibility-for-QQuickWidget.patch
=====================================
@@ -0,0 +1,565 @@
+From f2afdde302aeb895989a4fef58c6fa75fc93364f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= <morten.sorvig at qt.io>
+Date: Fri, 7 May 2021 10:07:50 +0200
+Subject: [PATCH 2/2] Implement accessibility for QQuickWidget
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The accessibility tree for the Qt Quick content should
+be rooted at the QQuickWidget, and not at the offscreen
+QQuickWindow.
+
+For this to be the case, several things must happen:
+  - QQuickWindow must not report the child interfaces
+  - QQuickWidget must report the child interfaces
+  - The child interfaces must report the QQuickWidget as the parent
+
+Create accessibility interfaces for QQuickWidget and
+and QQuickWigetOffscreenWindow (which now gets a proper
+subclass), where the QQuickWidget interface reports
+the child interfaces and the QQuickWigetOffscreenWindow
+reports no children
+
+Change the code in QAccessibleQuickItem to use the
+true (visible) window, where needed.
+
+Fixes: QTBUG-67290
+Change-Id: I387d0ef711138d248a8dd16eefc9839499b35eeb
+Reviewed-by: Jan Arve Sæther <jan-arve.saether at qt.io>
+Reviewed-by: Volker Hilsheimer <volker.hilsheimer at qt.io>
+(cherry picked from commit 41926e08d73ea6c4bbfc87a1dd52d2cdbc435c27)
+---
+ src/quick/accessible/qaccessiblequickitem.cpp |  29 +++--
+ src/quick/accessible/qaccessiblequickview_p.h |   2 +-
+ src/quickwidgets/qaccessiblequickwidget.cpp   | 110 ++++++++++++++++++
+ src/quickwidgets/qaccessiblequickwidget.h     |  84 +++++++++++++
+ .../qaccessiblequickwidgetfactory.cpp         |  60 ++++++++++
+ .../qaccessiblequickwidgetfactory_p.h         |  66 +++++++++++
+ src/quickwidgets/qquickwidget.cpp             |  18 ++-
+ src/quickwidgets/qquickwidget_p.h             |   8 ++
+ src/quickwidgets/quickwidgets.pro             |   8 +-
+ 9 files changed, 368 insertions(+), 17 deletions(-)
+ create mode 100644 src/quickwidgets/qaccessiblequickwidget.cpp
+ create mode 100644 src/quickwidgets/qaccessiblequickwidget.h
+ create mode 100644 src/quickwidgets/qaccessiblequickwidgetfactory.cpp
+ create mode 100644 src/quickwidgets/qaccessiblequickwidgetfactory_p.h
+
+diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
+index 85719fdc80..eb3df4d4cd 100644
+--- a/src/quick/accessible/qaccessiblequickitem.cpp
++++ b/src/quick/accessible/qaccessiblequickitem.cpp
+@@ -46,6 +46,7 @@
+ #include "QtQuick/private/qquicktextinput_p.h"
+ #include "QtQuick/private/qquickaccessibleattached_p.h"
+ #include "QtQuick/qquicktextdocument.h"
++#include "QtQuick/qquickrendercontrol.h"
+ QT_BEGIN_NAMESPACE
+ 
+ #if QT_CONFIG(accessibility)
+@@ -57,7 +58,19 @@ QAccessibleQuickItem::QAccessibleQuickItem(QQuickItem *item)
+ 
+ QWindow *QAccessibleQuickItem::window() const
+ {
+-    return item()->window();
++    QQuickWindow *window = item()->window();
++
++    // For QQuickWidget the above window will be the offscreen QQuickWindow,
++    // which is not a part of the accessibility tree. Detect this case and
++    // return the window for the QQuickWidget instead.
++    if (window && !window->handle()) {
++        if (QQuickRenderControl *renderControl = QQuickWindowPrivate::get(window)->renderControl) {
++            if (QWindow *renderWindow = renderControl->renderWindow(nullptr))
++                return renderWindow;
++        }
++    }
++
++    return window;
+ }
+ 
+ int QAccessibleQuickItem::childCount() const
+@@ -113,19 +126,15 @@ QAccessibleInterface *QAccessibleQuickItem::childAt(int x, int y) const
+ QAccessibleInterface *QAccessibleQuickItem::parent() const
+ {
+     QQuickItem *parent = item()->parentItem();
+-    QQuickWindow *window = item()->window();
+-    QQuickItem *ci = window ? window->contentItem() : nullptr;
++    QQuickWindow *itemWindow = item()->window();
++    QQuickItem *ci = itemWindow ? itemWindow->contentItem() : nullptr;
+     while (parent && !QQuickItemPrivate::get(parent)->isAccessible && parent != ci)
+         parent = parent->parentItem();
+ 
+     if (parent) {
+         if (parent == ci) {
+-            // Jump out to the scene widget if the parent is the root item.
+-            // There are two root items, QQuickWindow::rootItem and
+-            // QQuickView::declarativeRoot. The former is the true root item,
+-            // but is not a part of the accessibility tree. Check if we hit
+-            // it here and return an interface for the scene instead.
+-            return QAccessible::queryAccessibleInterface(window);
++            // Jump out to the window if the parent is the root item
++            return QAccessible::queryAccessibleInterface(window());
+         } else {
+             while (parent && !parent->d_func()->isAccessible)
+                 parent = parent->parentItem();
+@@ -188,7 +197,7 @@ QAccessible::State QAccessibleQuickItem::state() const
+     QRect viewRect_ = viewRect();
+     QRect itemRect = rect();
+ 
+-    if (viewRect_.isNull() || itemRect.isNull() || !item()->window() || !item()->window()->isVisible() ||!item()->isVisible() || qFuzzyIsNull(item()->opacity()))
++    if (viewRect_.isNull() || itemRect.isNull() || !window() || !window()->isVisible() ||!item()->isVisible() || qFuzzyIsNull(item()->opacity()))
+         state.invisible = true;
+     if (!viewRect_.intersects(itemRect))
+         state.offscreen = true;
+diff --git a/src/quick/accessible/qaccessiblequickview_p.h b/src/quick/accessible/qaccessiblequickview_p.h
+index 39ffcaf39c..8baa01330c 100644
+--- a/src/quick/accessible/qaccessiblequickview_p.h
++++ b/src/quick/accessible/qaccessiblequickview_p.h
+@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
+ 
+ #if QT_CONFIG(accessibility)
+ 
+-class QAccessibleQuickWindow : public QAccessibleObject
++class Q_QUICK_EXPORT QAccessibleQuickWindow : public QAccessibleObject
+ {
+ public:
+     QAccessibleQuickWindow(QQuickWindow *object);
+diff --git a/src/quickwidgets/qaccessiblequickwidget.cpp b/src/quickwidgets/qaccessiblequickwidget.cpp
+new file mode 100644
+index 0000000000..6f04d6693f
+--- /dev/null
++++ b/src/quickwidgets/qaccessiblequickwidget.cpp
+@@ -0,0 +1,110 @@
++/****************************************************************************
++**
++** Copyright (C) 2021 The Qt Company Ltd.
++** Contact: https://www.qt.io/licensing/
++**
++** This file is part of the QtQuick module of the Qt Toolkit.
++**
++** $QT_BEGIN_LICENSE:LGPL$
++** Commercial License Usage
++** Licensees holding valid commercial Qt licenses may use this file in
++** accordance with the commercial license agreement provided with the
++** Software or, alternatively, in accordance with the terms contained in
++** a written agreement between you and The Qt Company. For licensing terms
++** and conditions see https://www.qt.io/terms-conditions. For further
++** information use the contact form at https://www.qt.io/contact-us.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 3 as published by the Free Software
++** Foundation and appearing in the file LICENSE.LGPL3 included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU Lesser General Public License version 3 requirements
++** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
++**
++** GNU General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU
++** General Public License version 2.0 or (at your option) the GNU General
++** Public license version 3 or any later version approved by the KDE Free
++** Qt Foundation. The licenses are as published by the Free Software
++** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
++** included in the packaging of this file. Please review the following
++** information to ensure the GNU General Public License requirements will
++** be met: https://www.gnu.org/licenses/gpl-2.0.html and
++** https://www.gnu.org/licenses/gpl-3.0.html.
++**
++** $QT_END_LICENSE$
++**
++****************************************************************************/
++
++#include "qaccessiblequickwidget.h"
++
++#include "qquickwidget_p.h"
++
++QT_BEGIN_NAMESPACE
++
++#if QT_CONFIG(accessibility)
++
++QAccessibleQuickWidget::QAccessibleQuickWidget(QQuickWidget* widget)
++: QAccessibleWidget(widget)
++, m_accessibleWindow(QQuickWidgetPrivate::get(widget)->offscreenWindow)
++{
++    // NOTE: m_accessibleWindow is a QAccessibleQuickWindow, and not a
++    // QAccessibleQuickWidgetOffscreenWindow (defined below). This means
++    // it will return the Quick item child interfaces, which is what's needed here
++    // (unlike QAccessibleQuickWidgetOffscreenWindow, which will report 0 children).
++}
++
++QAccessibleInterface *QAccessibleQuickWidget::child(int index) const
++{
++    return m_accessibleWindow.child(index);
++}
++
++int QAccessibleQuickWidget::childCount() const
++{
++    return m_accessibleWindow.childCount();
++}
++
++int QAccessibleQuickWidget::indexOfChild(const QAccessibleInterface *iface) const
++{
++    return m_accessibleWindow.indexOfChild(iface);
++}
++
++QAccessibleInterface *QAccessibleQuickWidget::childAt(int x, int y) const
++{
++    return m_accessibleWindow.childAt(x, y);
++}
++
++QAccessibleQuickWidgetOffscreenWindow::QAccessibleQuickWidgetOffscreenWindow(QQuickWindow *window)
++:QAccessibleQuickWindow(window)
++{
++
++}
++
++QAccessibleInterface *QAccessibleQuickWidgetOffscreenWindow::child(int index) const
++{
++    Q_UNUSED(index);
++    return nullptr;
++}
++
++int QAccessibleQuickWidgetOffscreenWindow::childCount() const
++{
++    return 0;
++}
++
++int QAccessibleQuickWidgetOffscreenWindow::indexOfChild(const QAccessibleInterface *iface) const
++{
++    Q_UNUSED(iface);
++    return -1;
++}
++
++QAccessibleInterface *QAccessibleQuickWidgetOffscreenWindow::QAccessibleQuickWidgetOffscreenWindow::childAt(int x, int y) const
++{
++    Q_UNUSED(x);
++    Q_UNUSED(y);
++    return nullptr;
++}
++
++#endif // accessibility
++
++QT_END_NAMESPACE
+diff --git a/src/quickwidgets/qaccessiblequickwidget.h b/src/quickwidgets/qaccessiblequickwidget.h
+new file mode 100644
+index 0000000000..1f52c78c46
+--- /dev/null
++++ b/src/quickwidgets/qaccessiblequickwidget.h
+@@ -0,0 +1,84 @@
++/****************************************************************************
++**
++** Copyright (C) 2021 The Qt Company Ltd.
++** Contact: https://www.qt.io/licensing/
++**
++** This file is part of the QtQuick module of the Qt Toolkit.
++**
++** $QT_BEGIN_LICENSE:LGPL$
++** Commercial License Usage
++** Licensees holding valid commercial Qt licenses may use this file in
++** accordance with the commercial license agreement provided with the
++** Software or, alternatively, in accordance with the terms contained in
++** a written agreement between you and The Qt Company. For licensing terms
++** and conditions see https://www.qt.io/terms-conditions. For further
++** information use the contact form at https://www.qt.io/contact-us.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 3 as published by the Free Software
++** Foundation and appearing in the file LICENSE.LGPL3 included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU Lesser General Public License version 3 requirements
++** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
++**
++** GNU General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU
++** General Public License version 2.0 or (at your option) the GNU General
++** Public license version 3 or any later version approved by the KDE Free
++** Qt Foundation. The licenses are as published by the Free Software
++** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
++** included in the packaging of this file. Please review the following
++** information to ensure the GNU General Public License requirements will
++** be met: https://www.gnu.org/licenses/gpl-2.0.html and
++** https://www.gnu.org/licenses/gpl-3.0.html.
++**
++** $QT_END_LICENSE$
++**
++****************************************************************************/
++
++#ifndef QACCESSIBLEQUICKWIDGET_H
++#define QACCESSIBLEQUICKWIDGET_H
++
++#include "qquickwidget.h"
++#include <QtWidgets/qaccessiblewidget.h>
++
++#include <private/qaccessiblequickview_p.h>
++
++QT_BEGIN_NAMESPACE
++
++#if QT_CONFIG(accessibility)
++
++// These classes implement the QQuickWiget accessibility switcharoo,
++// where the child items of the QQuickWidgetOffscreenWindow are reported
++// as child accessible interfaces of the QAccessibleQuickWidget.
++class QAccessibleQuickWidget: public QAccessibleWidget
++{
++public:
++    QAccessibleQuickWidget(QQuickWidget* widget);
++
++    QAccessibleInterface *child(int index) const override;
++    int childCount() const override;
++    int indexOfChild(const QAccessibleInterface *iface) const override;
++    QAccessibleInterface *childAt(int x, int y) const override;
++
++private:
++    QAccessibleQuickWindow m_accessibleWindow;
++    Q_DISABLE_COPY(QAccessibleQuickWidget)
++};
++
++class QAccessibleQuickWidgetOffscreenWindow: public QAccessibleQuickWindow
++{
++public:
++    QAccessibleQuickWidgetOffscreenWindow(QQuickWindow *window);
++    QAccessibleInterface *child(int index) const override;
++    int childCount() const override;
++    int indexOfChild(const QAccessibleInterface *iface) const override;
++    QAccessibleInterface *childAt(int x, int y) const override;
++};
++
++#endif // accessibility
++
++QT_END_NAMESPACE
++
++#endif
+diff --git a/src/quickwidgets/qaccessiblequickwidgetfactory.cpp b/src/quickwidgets/qaccessiblequickwidgetfactory.cpp
+new file mode 100644
+index 0000000000..3756d0c27c
+--- /dev/null
++++ b/src/quickwidgets/qaccessiblequickwidgetfactory.cpp
+@@ -0,0 +1,60 @@
++/****************************************************************************
++**
++** Copyright (C) 2021 The Qt Company Ltd.
++** Contact: https://www.qt.io/licensing/
++**
++** This file is part of the QtQuick module of the Qt Toolkit.
++**
++** $QT_BEGIN_LICENSE:LGPL$
++** Commercial License Usage
++** Licensees holding valid commercial Qt licenses may use this file in
++** accordance with the commercial license agreement provided with the
++** Software or, alternatively, in accordance with the terms contained in
++** a written agreement between you and The Qt Company. For licensing terms
++** and conditions see https://www.qt.io/terms-conditions. For further
++** information use the contact form at https://www.qt.io/contact-us.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 3 as published by the Free Software
++** Foundation and appearing in the file LICENSE.LGPL3 included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU Lesser General Public License version 3 requirements
++** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
++**
++** GNU General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU
++** General Public License version 2.0 or (at your option) the GNU General
++** Public license version 3 or any later version approved by the KDE Free
++** Qt Foundation. The licenses are as published by the Free Software
++** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
++** included in the packaging of this file. Please review the following
++** information to ensure the GNU General Public License requirements will
++** be met: https://www.gnu.org/licenses/gpl-2.0.html and
++** https://www.gnu.org/licenses/gpl-3.0.html.
++**
++** $QT_END_LICENSE$
++**
++****************************************************************************/
++
++#include "qaccessiblequickwidgetfactory_p.h"
++#include "qaccessiblequickwidget.h"
++
++QT_BEGIN_NAMESPACE
++
++#if QT_CONFIG(accessibility)
++
++QAccessibleInterface *qAccessibleQuickWidgetFactory(const QString &classname, QObject *object)
++{
++    if (classname == QLatin1String("QQuickWidget")) {
++        return new QAccessibleQuickWidget(qobject_cast<QQuickWidget *>(object));
++    } else if (classname == QLatin1String("QQuickWidgetOffscreenWindow")) {
++        return new QAccessibleQuickWidgetOffscreenWindow(qobject_cast<QQuickWindow *>(object));
++    }
++    return 0;
++}
++
++#endif // accessibility
++
++QT_END_NAMESPACE
++
+diff --git a/src/quickwidgets/qaccessiblequickwidgetfactory_p.h b/src/quickwidgets/qaccessiblequickwidgetfactory_p.h
+new file mode 100644
+index 0000000000..8c63b09f81
+--- /dev/null
++++ b/src/quickwidgets/qaccessiblequickwidgetfactory_p.h
+@@ -0,0 +1,66 @@
++/****************************************************************************
++**
++** Copyright (C) 2021 The Qt Company Ltd.
++** Contact: https://www.qt.io/licensing/
++**
++** This file is part of the QtQuick module of the Qt Toolkit.
++**
++** $QT_BEGIN_LICENSE:LGPL$
++** Commercial License Usage
++** Licensees holding valid commercial Qt licenses may use this file in
++** accordance with the commercial license agreement provided with the
++** Software or, alternatively, in accordance with the terms contained in
++** a written agreement between you and The Qt Company. For licensing terms
++** and conditions see https://www.qt.io/terms-conditions. For further
++** information use the contact form at https://www.qt.io/contact-us.
++**
++** GNU Lesser General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU Lesser
++** General Public License version 3 as published by the Free Software
++** Foundation and appearing in the file LICENSE.LGPL3 included in the
++** packaging of this file. Please review the following information to
++** ensure the GNU Lesser General Public License version 3 requirements
++** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
++**
++** GNU General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU
++** General Public License version 2.0 or (at your option) the GNU General
++** Public license version 3 or any later version approved by the KDE Free
++** Qt Foundation. The licenses are as published by the Free Software
++** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
++** included in the packaging of this file. Please review the following
++** information to ensure the GNU General Public License requirements will
++** be met: https://www.gnu.org/licenses/gpl-2.0.html and
++** https://www.gnu.org/licenses/gpl-3.0.html.
++**
++** $QT_END_LICENSE$
++**
++****************************************************************************/
++
++#include <QtGui/qaccessible.h>
++
++#ifndef QACCESSIBLEQUICKWIDGETFACTORY_H
++#define QACCESSIBLEQUICKWIDGETFACTORY_H
++
++//
++//  W A R N I N G
++//  -------------
++//
++// This file is not part of the Qt API.  It exists purely as an
++// implementation detail.  This header file may change from version to
++// version without notice, or even be removed.
++//
++// We mean it.
++//
++
++QT_BEGIN_NAMESPACE
++
++#if QT_CONFIG(accessibility)
++
++QAccessibleInterface *qAccessibleQuickWidgetFactory(const QString &classname, QObject *object);
++
++#endif
++
++QT_END_NAMESPACE
++
++#endif
+diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
+index 223d91f579..9c97b43518 100644
+--- a/src/quickwidgets/qquickwidget.cpp
++++ b/src/quickwidgets/qquickwidget.cpp
+@@ -39,6 +39,7 @@
+ 
+ #include "qquickwidget.h"
+ #include "qquickwidget_p.h"
++#include "qaccessiblequickwidgetfactory_p.h"
+ 
+ #include "private/qquickwindow_p.h"
+ #include "private/qquickitem_p.h"
+@@ -75,9 +76,16 @@
+ 
+ QT_BEGIN_NAMESPACE
+ 
++QQuickWidgetOffscreenWindow::QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control)
++:QQuickWindow(dd, control)
++{
++    setTitle(QString::fromLatin1("Offscreen"));
++    setObjectName(QString::fromLatin1("QQuickOffScreenWindow"));
++}
++
+ // override setVisble to prevent accidental offscreen window being created
+ // by base class.
+-class QQuickOffcreenWindowPrivate: public QQuickWindowPrivate {
++class QQuickWidgetOffscreenWindowPrivate: public QQuickWindowPrivate {
+ public:
+     void setVisible(bool visible) override {
+         Q_Q(QWindow);
+@@ -105,10 +113,8 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
+     Q_Q(QQuickWidget);
+ 
+     renderControl = new QQuickWidgetRenderControl(q);
+-    offscreenWindow = new QQuickWindow(*new QQuickOffcreenWindowPrivate(),renderControl);
++    offscreenWindow = new QQuickWidgetOffscreenWindow(*new QQuickWidgetOffscreenWindowPrivate(), renderControl);
+     offscreenWindow->setScreen(q->screen());
+-    offscreenWindow->setTitle(QString::fromLatin1("Offscreen"));
+-    offscreenWindow->setObjectName(QString::fromLatin1("QQuickOffScreenWindow"));
+     // Do not call create() on offscreenWindow.
+ 
+     // Check if the Software Adaptation is being used
+@@ -139,6 +145,10 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
+     QWidget::connect(offscreenWindow, &QQuickWindow::focusObjectChanged, q, &QQuickWidget::propagateFocusObjectChanged);
+     QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
+     QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
++
++#if QT_CONFIG(accessibility)
++    QAccessible::installFactory(&qAccessibleQuickWidgetFactory);
++#endif
+ }
+ 
+ void QQuickWidgetPrivate::ensureEngine() const
+diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h
+index 881f7f9220..1a946bcc71 100644
+--- a/src/quickwidgets/qquickwidget_p.h
++++ b/src/quickwidgets/qquickwidget_p.h
+@@ -148,6 +148,14 @@ public:
+     bool forceFullUpdate;
+ };
+ 
++class QQuickWidgetOffscreenWindow: public QQuickWindow
++{
++    Q_OBJECT
++
++public:
++    QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control);
++};
++
+ QT_END_NAMESPACE
+ 
+ #endif // QQuickWidget_P_H
+diff --git a/src/quickwidgets/quickwidgets.pro b/src/quickwidgets/quickwidgets.pro
+index 2438e577ae..f46deb54ac 100644
+--- a/src/quickwidgets/quickwidgets.pro
++++ b/src/quickwidgets/quickwidgets.pro
+@@ -7,9 +7,13 @@ DEFINES   += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES QT_NO_FO
+ HEADERS += \
+     qquickwidget.h \
+     qquickwidget_p.h \
+-    qtquickwidgetsglobal.h
++    qtquickwidgetsglobal.h \
++    qaccessiblequickwidget.h \
++    qaccessiblequickwidgetfactory_p.h
+ 
+ SOURCES += \
+-    qquickwidget.cpp
++    qquickwidget.cpp \
++    qaccessiblequickwidget.cpp \
++    qaccessiblequickwidgetfactory.cpp
+ 
+ load(qt_module)
+-- 
+2.34.1
+


=====================================
contrib/src/qtdeclarative/rules.mak
=====================================
@@ -21,6 +21,8 @@ $(TARBALLS)/qtdeclarative-everywhere-src-$(QTDECLARATIVE_VERSION).tar.xz:
 
 qtdeclarative: qtdeclarative-everywhere-src-$(QTDECLARATIVE_VERSION).tar.xz .sum-qtdeclarative
 	$(UNPACK)
+	$(APPLY) $(SRC)/qtdeclarative/0001-Make-sure-QQuickWidget-and-its-offscreen-window-s-sc.patch
+	$(APPLY) $(SRC)/qtdeclarative/0002-Implement-accessibility-for-QQuickWidget.patch
 	# do not build qml.exe and other useless tools
 	sed -i.orig 's,!wasm:!rtems ,!wasm:!rtems:!static ,' "$(UNPACK_DIR)/tools/tools.pro"
 	$(MOVE)


=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -81,6 +81,18 @@ endif
 if HAVE_QT5_GTK
 libqt_plugin_la_CPPFLAGS += -DQT5_HAS_GTK
 endif
+if HAVE_QT5_DECLARATIVE_PRIVATE
+libqt_plugin_la_CPPFLAGS += -DQT5_DECLARATIVE_PRIVATE \
+	-I$(QT_INCLUDE_DIRECTORY)/QtCore/$(QT_VERSION) \
+	-I$(QT_INCLUDE_DIRECTORY)/QtCore/$(QT_VERSION)/QtCore \
+	-I$(QT_INCLUDE_DIRECTORY)/QtGui/$(QT_VERSION) \
+	-I$(QT_INCLUDE_DIRECTORY)/QtGui/$(QT_VERSION)/QtGui \
+	-I$(QT_INCLUDE_DIRECTORY)/QtQml/$(QT_VERSION) \
+	-I$(QT_INCLUDE_DIRECTORY)/QtQml/$(QT_VERSION)/QtQml \
+	-I$(QT_INCLUDE_DIRECTORY)/QtQuick/$(QT_VERSION) \
+	-I$(QT_INCLUDE_DIRECTORY)/QtQuick/$(QT_VERSION)/QtQuick
+
+endif
 
 libqt_plugin_la_SOURCES = \
 	gui/qt/qt.cpp gui/qt/qt.hpp gui/qt/plugins.hpp \
@@ -152,6 +164,10 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/dialogs/playlists/playlists.cpp gui/qt/dialogs/playlists/playlists.hpp \
 	gui/qt/maininterface/compositor.hpp \
 	gui/qt/maininterface/compositor.cpp \
+	gui/qt/maininterface/compositor_common.hpp \
+	gui/qt/maininterface/compositor_common.cpp \
+	gui/qt/maininterface/compositor_accessibility.cpp \
+	gui/qt/maininterface/compositor_accessibility.hpp \
 	gui/qt/maininterface/compositor_dummy.hpp \
 	gui/qt/maininterface/compositor_dummy.cpp \
 	gui/qt/maininterface/interface_window_handler.cpp \
@@ -428,6 +444,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/dialogs/toolbar/controlbar_profile_model.moc.cpp \
 	gui/qt/dialogs/playlists/playlists.moc.cpp \
 	gui/qt/maininterface/compositor.moc.cpp \
+	gui/qt/maininterface/compositor_common.moc.cpp \
 	gui/qt/maininterface/compositor_dummy.moc.cpp \
 	gui/qt/maininterface/interface_window_handler.moc.cpp \
 	gui/qt/maininterface/mainctx.moc.cpp \


=====================================
modules/gui/qt/maininterface/compositor.hpp
=====================================
@@ -43,6 +43,7 @@ class QQmlComponent;
 class QWindow;
 class QQuickItem;
 class QQuickView;
+class QQuickWindow;
 
 namespace vlc {
 
@@ -100,6 +101,7 @@ public:
 
         virtual QQuickItem * activeFocusItem() const = 0;
     };
+
 public:
     explicit CompositorVideo(qt_intf_t* p_intf, QObject* parent = nullptr);
     virtual ~CompositorVideo();


=====================================
modules/gui/qt/maininterface/compositor_accessibility.cpp
=====================================
@@ -0,0 +1,282 @@
+/*****************************************************************************
+ * Copyright (C) 2023 the VideoLAN team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include <QWindow>
+#include <QGuiApplication>
+#include <QQuickItem>
+
+#if !defined(QT_NO_ACCESSIBILITY) && defined(QT5_DECLARATIVE_PRIVATE)
+
+#include <QAccessibleObject>
+
+#include <private/qquickitem_p.h>
+
+#include "compositor_accessibility.hpp"
+#include "compositor.hpp"
+
+#ifdef QT5_HAS_X11_COMPOSITOR
+#  include "compositor_x11_renderwindow.hpp"
+#endif
+#ifdef HAVE_DCOMP_H
+#  include "compositor_dcomp_uisurface.hpp"
+#endif
+
+namespace vlc {
+
+/*
+ * we could have use QAccessibleQuickWindow like in QAccessibleQuickWidget
+ * but QAccessibleQuickWindow is not publicly exposed in the library, so we
+ * mimic the behavior of QAccessibleQuickWindow directly
+ */
+
+
+static void unignoredChildren(QQuickItem *item, QList<QQuickItem *> *items)
+{
+    const QList<QQuickItem*> childItems = item->childItems();
+    for (QQuickItem *child : childItems)
+    {
+        if (QQuickItemPrivate::get(child)->isAccessible)
+            items->append(child);
+        else
+            unignoredChildren(child, items);
+    }
+}
+
+static QList<QQuickItem *> accessibleUnignoredChildren(QQuickItem *item)
+{
+    QList<QQuickItem *> items;
+    unignoredChildren(item, &items);
+    return items;
+}
+
+
+class QAccessibleRenderWindow: public QAccessibleObject
+{
+public:
+    QAccessibleRenderWindow(QWindow* window, AccessibleRenderWindow* renderWindow)
+        : QAccessibleObject(window)
+        , m_window(renderWindow->getOffscreenWindow())
+    {
+    }
+
+    QAccessibleInterface* parent() const override
+    {
+        // we assume to be a top level window...
+        return QAccessible::queryAccessibleInterface(qApp);
+    }
+
+    QList<QQuickItem *> rootItems() const
+    {
+        if (QQuickItem *ci = m_window->contentItem())
+            return accessibleUnignoredChildren(ci);
+        return QList<QQuickItem *>();
+    }
+
+
+    QAccessibleInterface* child(int index) const override
+    {
+        const QList<QQuickItem*> &kids = rootItems();
+        if (index >= 0 && index < kids.count())
+            return QAccessible::queryAccessibleInterface(kids.at(index));
+        return nullptr;
+    }
+
+    int childCount() const override
+    {
+        return rootItems().count();
+    }
+
+    int indexOfChild(const QAccessibleInterface *iface) const override
+    {
+        int i = -1;
+        if (iface)
+        {
+            const QList<QQuickItem *> &roots = rootItems();
+            i = roots.count() - 1;
+            while (i >= 0)
+            {
+                if (iface->object() == roots.at(i))
+                    break;
+                --i;
+            }
+        }
+        return i;
+    }
+
+    QAccessibleInterface *childAt(int x, int y) const override
+    {
+        for (int i = childCount() - 1; i >= 0; --i)
+        {
+            QAccessibleInterface *childIface = child(i);
+            if (childIface && !childIface->state().invisible)
+            {
+                if (QAccessibleInterface *iface = childIface->childAt(x, y))
+                    return iface;
+                if (childIface->rect().contains(x, y))
+                    return childIface;
+            }
+        }
+        return nullptr;
+    }
+
+    QString text(QAccessible::Text) const override
+    {
+        return window()->title();
+    }
+
+    QRect rect() const override
+    {
+        return QRect(window()->x(), window()->y(), window()->width(), window()->height());
+    }
+
+    QAccessible::Role role() const override
+    {
+        return QAccessible::Window;
+    }
+
+    QAccessible::State state() const override
+    {
+
+        QAccessible::State st;
+        if (window() == QGuiApplication::focusWindow())
+            st.active = true;
+        if (!window()->isVisible())
+            st.invisible = true;
+        return st;
+    }
+
+    QWindow* window() const override
+    {
+        return static_cast<QWindow*>(object());
+    }
+
+private:
+    QQuickWindow* m_window;
+};
+
+
+/*
+ * DCompOffscreenWindow is a top window, mark it as unacessible so it won't
+ * be introspected by a11y, the QML scene is actually accessible though QAccessibleRenderWindow
+ */
+class QAccessibleOffscreenWindow: public QAccessibleObject
+{
+public:
+    QAccessibleOffscreenWindow(QQuickWindow *window)
+        : QAccessibleObject(window)
+    {
+    }
+
+    QAccessibleInterface* parent() const override
+    {
+        // we assume to be a top level window...
+        return QAccessible::queryAccessibleInterface(qApp);
+    }
+
+    QAccessibleInterface* child(int) const override
+    {
+        return nullptr;
+    }
+
+    int childCount() const override
+    {
+        return 0;
+    }
+
+    int indexOfChild(const QAccessibleInterface *) const override
+    {
+        return -1;
+    }
+
+    QAccessibleInterface *childAt(int, int) const override
+    {
+        return nullptr;
+    }
+
+    QAccessibleInterface *focusChild() const override
+    {
+        return nullptr;
+    }
+
+    QString text(QAccessible::Text) const override
+    {
+        return window()->title();
+    }
+
+    QRect rect() const override
+    {
+        return QRect(window()->x(), window()->y(), window()->width(), window()->height());
+    }
+
+    QAccessible::Role role() const override
+    {
+        return QAccessible::Window;
+    }
+
+    QAccessible::State state() const override
+    {
+
+        QAccessible::State st;
+        if (window() == QGuiApplication::focusWindow())
+            st.active = true;
+        if (!window()->isVisible())
+            st.invisible = true;
+        return st;
+    }
+
+private:
+    QWindow* window() const override
+    {
+        return static_cast<QWindow*>(object());
+    }
+};
+
+QAccessibleInterface* compositionAccessibleFactory(const QString &classname, QObject *object)
+{
+#ifdef QT5_HAS_X11_COMPOSITOR
+    if (classname == QLatin1String("vlc::CompositorX11RenderWindow"))
+    {
+
+        CompositorX11RenderWindow* renderWindow =  qobject_cast<CompositorX11RenderWindow *>(object);
+        assert(renderWindow);
+        return new QAccessibleRenderWindow(renderWindow, renderWindow);
+    }
+#endif
+
+#ifdef HAVE_DCOMP_H
+    if (classname == QLatin1String("vlc::DCompRenderWindow"))
+    {
+
+        DCompRenderWindow* renderWindow =  qobject_cast<DCompRenderWindow *>(object);
+        assert(renderWindow);
+        return new QAccessibleRenderWindow(renderWindow, renderWindow);
+    }
+#endif
+
+    if (classname == QLatin1String("vlc::CompositorOffscreenWindow")
+        || (classname == QLatin1String("vlc::DCompOffscreenWindow")) )
+    {
+        return new QAccessibleOffscreenWindow(qobject_cast<QQuickWindow *>(object));
+    }
+
+    return nullptr;
+}
+
+}
+
+ #endif


=====================================
modules/gui/qt/maininterface/compositor_accessibility.hpp
=====================================
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (C) 2023 the VideoLAN team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef COMPOSITOR_ACCESSIBLITY_H
+#define COMPOSITOR_ACCESSIBLITY_H
+
+#include <QString>
+
+class QObject;
+class QAccessibleInterface;
+class QQuickWindow;
+
+namespace vlc {
+
+class AccessibleRenderWindow
+{
+public:
+    virtual ~AccessibleRenderWindow()  = default;
+    virtual QQuickWindow* getOffscreenWindow() const = 0;
+};
+
+
+#if !defined(QT_NO_ACCESSIBILITY) && defined(QT5_DECLARATIVE_PRIVATE)
+
+QAccessibleInterface* compositionAccessibleFactory(const QString &classname, QObject *object);
+
+#endif
+
+}
+
+#endif /* COMPOSITOR_ACCESSIBLITY_H */


=====================================
modules/gui/qt/maininterface/compositor_common.cpp
=====================================
@@ -0,0 +1,172 @@
+/*****************************************************************************
+ * Copyright (C) 2023 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+
+#include "compositor_common.hpp"
+
+#include <QBackingStore>
+#ifndef QT_NO_ACCESSIBILITY
+#include <QAccessible>
+#endif
+
+#ifdef QT5_DECLARATIVE_PRIVATE
+#include <private/qquickwindow_p.h>
+#endif
+
+using namespace vlc;
+
+DummyRenderWindow::DummyRenderWindow(QWindow* parent)
+    : QWindow(parent)
+{
+    setSurfaceType(RasterSurface);
+    QSurfaceFormat fmt = format();
+    fmt.setAlphaBufferSize(8);
+    setFormat(fmt);
+}
+
+QAccessibleInterface* DummyRenderWindow::accessibleRoot() const
+{
+#ifndef QT_NO_ACCESSIBILITY
+    QAccessibleInterface* iface = QAccessible::queryAccessibleInterface(
+                const_cast<DummyRenderWindow*>(this));
+    return iface;
+#else
+    return nullptr;
+#endif
+}
+
+bool DummyRenderWindow::event(QEvent* event)
+{
+    switch (event->type() )
+    {
+    case QEvent::UpdateRequest:
+        render();
+        return true;
+    case QEvent::Expose:
+        if (isExposed())
+            requestUpdate();
+        return true;
+    default:
+        break;
+    }
+
+    return QWindow::event(event);
+}
+
+void DummyRenderWindow::resizeEvent(QResizeEvent* resizeEvent)
+{
+    if (!m_backingStore)
+        return;
+    if (!m_initialized)
+        init();
+    m_backingStore->resize(resizeEvent->size());
+}
+
+void DummyRenderWindow::init()
+{
+    if (m_initialized)
+        return;
+    m_initialized = true;
+    m_backingStore = new QBackingStore(this);
+}
+
+void DummyRenderWindow::render()
+{
+    if (!m_initialized)
+        init();
+    if (!isExposed())
+        return;
+    QRect rect(0, 0, width(), height());
+    if (m_backingStore->size() != size())
+    {
+        m_backingStore->resize(size());
+    }
+
+    //note that we don't need to actually use our backing store
+    //drawing anything would just lead to flickering
+    m_backingStore->flush(QRect(0, 0, 1, 1));
+    return;
+}
+
+#ifdef QT5_DECLARATIVE_PRIVATE
+
+class OffscreenWindowPrivate: public QQuickWindowPrivate
+{
+public:
+    void setVisible(bool newVisible) override {
+        Q_Q(QWindow);
+        if (visible != newVisible)
+        {
+            visible = newVisible;
+            q->visibleChanged(newVisible);
+            // this stays always invisible
+            visibility = newVisible ? QWindow::Windowed : QWindow::Hidden;
+            q->visibilityChanged(visibility); // workaround for QTBUG-49054
+        }
+    }
+};
+
+CompositorOffscreenWindow::CompositorOffscreenWindow(QQuickRenderControl* renderControl)
+    : QQuickWindow(* (new OffscreenWindowPrivate()), renderControl)
+{
+}
+
+static Qt::WindowState resolveWindowState(Qt::WindowStates states)
+{
+    // No more than one of these 3 can be set
+    if (states & Qt::WindowMinimized)
+        return Qt::WindowMinimized;
+    if (states & Qt::WindowMaximized)
+        return Qt::WindowMaximized;
+    if (states & Qt::WindowFullScreen)
+        return Qt::WindowFullScreen;
+    // No state means "windowed" - we ignore Qt::WindowActive
+    return Qt::WindowNoState;
+}
+
+void CompositorOffscreenWindow::setWindowStateExt(Qt::WindowState state)
+{
+    QWindow::setWindowState(resolveWindowState(state));
+}
+
+void CompositorOffscreenWindow::setPseudoVisible(bool visible)
+{
+    setVisible(visible);
+}
+
+#else
+
+CompositorOffscreenWindow::CompositorOffscreenWindow(QQuickRenderControl* renderControl)
+: QQuickWindow(renderControl)
+{
+}
+
+void CompositorOffscreenWindow::setWindowStateExt(Qt::WindowState state)
+{
+    QWindow::setWindowState(state);
+}
+
+//don't set the window visible, this would create the window, and show make it actually visible
+void CompositorOffscreenWindow::setPseudoVisible(bool)
+{
+}
+
+#endif
+
+
+


=====================================
modules/gui/qt/maininterface/compositor_common.hpp
=====================================
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * Copyright (C) 2023 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef COMPOSITOR_COMMON_HPP
+#define COMPOSITOR_COMMON_HPP
+
+#include <QWindow>
+#include <QQuickWindow>
+
+namespace vlc {
+
+/**
+ * a minimal window with no content
+ * this may be useful on linux platform to provide a
+ * window which can be drawn into, using a bare QWindow
+ * usually freeze on resize
+ */
+class DummyRenderWindow : public QWindow
+{
+    Q_OBJECT
+public:
+    explicit DummyRenderWindow(QWindow* parent = nullptr);
+
+    virtual QAccessibleInterface *accessibleRoot() const override;
+
+protected:
+    bool event(QEvent *event) override;
+
+    void resizeEvent(QResizeEvent *resizeEvent) override;
+
+private:
+    void init();
+    void render();
+
+    QBackingStore* m_backingStore = nullptr;
+    bool m_initialized = false;;
+};
+
+
+/**
+ * @brief The CompositorOffscreenWindow class allows to fake the visiblilty
+ * of the the QQuickWindow, note that this feature will only work if QT5_DECLARATIVE_PRIVATE
+ * are available
+ */
+class CompositorOffscreenWindow : public QQuickWindow
+{
+    Q_OBJECT
+public:
+    explicit CompositorOffscreenWindow(QQuickRenderControl* renderControl);
+
+    void setWindowStateExt(Qt::WindowState);
+
+    void setPseudoVisible(bool visible);
+};
+
+
+}
+
+#endif /* COMPOSITOR_COMMON_HPP */


=====================================
modules/gui/qt/maininterface/compositor_dcomp.cpp
=====================================
@@ -252,7 +252,7 @@ bool CompositorDirectComposition::makeMainInterface(MainCtx* mainCtx)
         bool ret;
         m_mainCtx = mainCtx;
 
-        m_rootWindow = new QWindow();
+        m_rootWindow = new DCompRenderWindow();
 
         m_videoWindowHandler = std::make_unique<VideoWindowHandler>(m_intf);
         m_videoWindowHandler->setWindow( m_rootWindow );


=====================================
modules/gui/qt/maininterface/compositor_dcomp.hpp
=====================================
@@ -70,7 +70,7 @@ protected:
     void windowDestroy() override;
 
 private:
-    QWindow* m_rootWindow = nullptr;
+    DCompRenderWindow* m_rootWindow = nullptr;
 
     std::unique_ptr<WinTaskbarWidget> m_taskbarWidget;
 


=====================================
modules/gui/qt/maininterface/compositor_dcomp_uisurface.cpp
=====================================
@@ -33,6 +33,9 @@
 #include <d3dcompiler.h>
 #include <comdef.h>
 
+#include "compositor_common.hpp""
+#include "compositor_accessibility.hpp"
+
 namespace vlc {
 
 using namespace Microsoft::WRL;
@@ -138,17 +141,35 @@ private:
     HINSTANCE                 m_compiler_dll = nullptr;
 };
 
+QAccessibleInterface* DCompRenderWindow::accessibleRoot() const
+{
+    QAccessibleInterface* iface = QAccessible::queryAccessibleInterface(
+        const_cast<DCompRenderWindow*>(this));
+    return iface;
+}
+
+void DCompRenderWindow::setOffscreenWindow(CompositorOffscreenWindow* window)
+{
+    m_offscreenWindow = window;
+}
+
+QQuickWindow* DCompRenderWindow::getOffscreenWindow() const
+{
+    return m_offscreenWindow;
+}
+
 CompositorDCompositionUISurface::CompositorDCompositionUISurface(qt_intf_t* p_intf,
-                                                                 QWindow* window,
+                                                                 DCompRenderWindow* window,
                                                                  Microsoft::WRL::ComPtr<IDCompositionVisual> dcVisual,
                                                                  QObject* parent)
     : QObject(parent)
     , m_intf(p_intf)
     , m_dcUiVisual(dcVisual)
-    , m_rootWindow(window)
+    , m_renderWindow(window)
 {
 }
 
+
 bool CompositorDCompositionUISurface::init()
 {
     EGLBoolean eglRet;
@@ -161,7 +182,7 @@ bool CompositorDCompositionUISurface::init()
     format.setAlphaBufferSize(8);
 
     m_context = new QOpenGLContext(this);
-    m_context->setScreen(m_rootWindow->screen());
+    m_context->setScreen(m_renderWindow->screen());
     m_context->setFormat(format);
     ret = m_context->create();
     if (!ret || !m_context->isValid())
@@ -198,13 +219,16 @@ bool CompositorDCompositionUISurface::init()
     m_uiOffscreenSurface->setFormat(format);;
     m_uiOffscreenSurface->create();
 
-    m_uiRenderControl = new CompositorDCompositionRenderControl(m_rootWindow);
+    m_uiRenderControl = new CompositorDCompositionRenderControl(m_renderWindow);
+
+    m_uiWindow = new CompositorOffscreenWindow(m_uiRenderControl);
 
-    m_uiWindow = new QQuickWindow(m_uiRenderControl);
     m_uiWindow->setDefaultAlphaBuffer(true);
     m_uiWindow->setFormat(format);
     m_uiWindow->setClearBeforeRendering(false);
 
+    m_renderWindow->setOffscreenWindow(m_uiWindow);
+
     m_d3dCompiler = std::make_shared<OurD3DCompiler>();
     ret = m_d3dCompiler->init(VLC_OBJECT(m_intf));
     if (!ret) {
@@ -212,8 +236,8 @@ bool CompositorDCompositionUISurface::init()
         return false;
     }
 
-    qreal dpr = m_rootWindow->devicePixelRatio();
-    ret = initialiseD3DSwapchain(dpr * m_rootWindow->width(), dpr * m_rootWindow->height());
+    qreal dpr = m_renderWindow->devicePixelRatio();
+    ret = initialiseD3DSwapchain(dpr * m_renderWindow->width(), dpr * m_renderWindow->height());
     if (!ret)
         return false;
 
@@ -225,10 +249,15 @@ bool CompositorDCompositionUISurface::init()
 
     connect(m_uiWindow, &QQuickWindow::sceneGraphInitialized, this, &CompositorDCompositionUISurface::createFbo);
     connect(m_uiWindow, &QQuickWindow::sceneGraphInvalidated, this, &CompositorDCompositionUISurface::destroyFbo);
+
+    connect(m_uiWindow, &QQuickWindow::focusObjectChanged, this, &CompositorDCompositionUISurface::forwardFocusObjectChanged);
+
     connect(m_uiRenderControl, &QQuickRenderControl::renderRequested, this, &CompositorDCompositionUISurface::requestUpdate);
     connect(m_uiRenderControl, &QQuickRenderControl::sceneChanged, this, &CompositorDCompositionUISurface::requestUpdate);
 
-    m_rootWindow->installEventFilter(this);
+    QAccessible::installFactory(&compositionAccessibleFactory);
+
+    m_renderWindow->installEventFilter(this);
     return true;
 }
 
@@ -525,7 +554,7 @@ void CompositorDCompositionUISurface::render()
 {
     EGLBoolean eglRet;
 
-    QSize realSize = m_rootWindow->size() * m_rootWindow->devicePixelRatio();
+    QSize realSize = m_renderWindow->size() * m_renderWindow->devicePixelRatio();
     if (realSize != m_surfaceSize)
     {
         m_surfaceSize = realSize;
@@ -609,22 +638,36 @@ static void remapInputMethodQueryEvent(QObject *object, QInputMethodQueryEvent *
     }
 }
 
+
+
+
 bool CompositorDCompositionUISurface::eventFilter(QObject* object, QEvent* event)
 {
-    if (object != m_rootWindow)
+    if (object != m_renderWindow)
         return false;
 
     switch (event->type()) {
     case QEvent::Move:
     case QEvent::Show:
+        //offscreen window won't be really visible
+        m_uiWindow->setPseudoVisible(true);
         updatePosition();
         break;
 
+    case QEvent::Hide:
+        m_uiWindow->setPseudoVisible(false);
+        break;
+
     case QEvent::Resize:
         updateSizes();
         forceRender();
         break;
 
+    case QEvent::FocusAboutToChange:
+        return QCoreApplication::sendEvent(m_uiWindow, event);
+    case QEvent::WindowStateChange:
+        m_uiWindow->setWindowStateExt(m_renderWindow->windowState());
+        break;
     case QEvent::WindowActivate:
     case QEvent::WindowDeactivate:
     case QEvent::Leave:
@@ -639,6 +682,10 @@ bool CompositorDCompositionUISurface::eventFilter(QObject* object, QEvent* event
         return ret;
     }
 
+    case QEvent::FocusIn:
+    case QEvent::FocusOut:
+        return QCoreApplication::sendEvent(m_uiWindow, event);
+
     case QEvent::InputMethod:
         return QCoreApplication::sendEvent(m_uiWindow->focusObject(), event);
     case QEvent::InputMethodQuery:
@@ -665,6 +712,9 @@ bool CompositorDCompositionUISurface::eventFilter(QObject* object, QEvent* event
         QCoreApplication::sendEvent(m_uiWindow, &mappedEvent);
         return true;
     }
+
+    case QEvent::ShortcutOverride:
+
     case QEvent::Wheel:
     case QEvent::HoverEnter:
     case QEvent::HoverLeave:
@@ -689,8 +739,9 @@ bool CompositorDCompositionUISurface::eventFilter(QObject* object, QEvent* event
         return QCoreApplication::sendEvent(m_uiWindow, event);
 
     case QEvent::ScreenChangeInternal:
-        m_uiWindow->setScreen(m_rootWindow->screen());
+        m_uiWindow->setScreen(m_renderWindow->screen());
         break;
+
     default:
         break;
     }
@@ -700,7 +751,7 @@ bool CompositorDCompositionUISurface::eventFilter(QObject* object, QEvent* event
 void CompositorDCompositionUISurface::createFbo()
 {
     //write to the immediate context
-    m_uiWindow->setRenderTarget(0, m_rootWindow->size());
+    m_uiWindow->setRenderTarget(0, m_renderWindow->size());
 }
 
 void CompositorDCompositionUISurface::destroyFbo()
@@ -709,8 +760,8 @@ void CompositorDCompositionUISurface::destroyFbo()
 
 void CompositorDCompositionUISurface::updateSizes()
 {
-    qreal dpr = m_rootWindow->devicePixelRatio();
-    QSize windowSize = m_rootWindow->size();
+    qreal dpr = m_renderWindow->devicePixelRatio();
+    QSize windowSize = m_renderWindow->size();
 
     resizeSwapchain(windowSize.width() * dpr, windowSize.height() * dpr);
     updateSharedTexture(windowSize.width() * dpr, windowSize.height() * dpr);
@@ -722,7 +773,7 @@ void CompositorDCompositionUISurface::updateSizes()
 
 void CompositorDCompositionUISurface::updatePosition()
 {
-    QPoint windowPosition = m_rootWindow->mapToGlobal(QPoint(0,0));
+    QPoint windowPosition = m_renderWindow->mapToGlobal(QPoint(0,0));
     if (m_uiWindow->position() != windowPosition)
         m_uiWindow->setPosition(windowPosition);
 }
@@ -736,11 +787,19 @@ void CompositorDCompositionUISurface::requestUpdate()
     }
 }
 
+QQuickWindow* CompositorDCompositionUISurface::getOffscreenWindow() const {
+    return m_uiWindow;
+}
+
 void CompositorDCompositionUISurface::handleScreenChange()
 {
-    msg_Info(m_intf, "handle screen change");
-    m_uiWindow->setGeometry(0, 0, m_rootWindow->width(), m_rootWindow->height());;
+    m_uiWindow->setGeometry(0, 0, m_renderWindow->width(), m_renderWindow->height());;
     requestUpdate();
 }
 
+void CompositorDCompositionUISurface::forwardFocusObjectChanged(QObject* object)
+{
+    m_renderWindow->focusObjectChanged(object);
+}
+
 }


=====================================
modules/gui/qt/maininterface/compositor_dcomp_uisurface.hpp
=====================================
@@ -59,9 +59,29 @@
 
 #include "qt.hpp"
 #include "compositor.hpp"
+#include "compositor_accessibility.hpp"
 
 namespace vlc {
 
+class CompositorOffscreenWindow;
+
+//on screen window
+class DCompRenderWindow : public QWindow, public AccessibleRenderWindow
+{
+    Q_OBJECT
+public:
+#ifndef QT_NO_ACCESSIBILITY
+    QAccessibleInterface* accessibleRoot() const override;
+#endif
+
+    void setOffscreenWindow(CompositorOffscreenWindow* window);
+    QQuickWindow* getOffscreenWindow() const override;
+
+private:
+    CompositorOffscreenWindow* m_offscreenWindow = nullptr;
+};
+
+
 class CompositorDCompositionRenderControl : public QQuickRenderControl
 {
     Q_OBJECT
@@ -85,7 +105,7 @@ class CompositorDCompositionUISurface : public QObject, public CompositorVideo::
     Q_OBJECT
 public:
     explicit CompositorDCompositionUISurface(qt_intf_t* p_intf,
-                                             QWindow* window,
+                                             DCompRenderWindow* window,
                                              Microsoft::WRL::ComPtr<IDCompositionVisual> dcVisual,
                                              QObject *parent = nullptr);
 
@@ -94,6 +114,7 @@ public:
     bool init();
 
     QQmlEngine* engine() const override { return m_qmlEngine; }
+    QQuickWindow* getOffscreenWindow() const;
 
     void setContent(QQmlComponent* component,  QQuickItem* rootItem) override;
 
@@ -113,6 +134,7 @@ private:
     void forceRender();
 
     void handleScreenChange();
+    void forwardFocusObjectChanged(QObject* object);
 
     void createFbo();
     void destroyFbo();
@@ -121,6 +143,8 @@ private:
     void updatePosition();
 
 private:
+    friend class DCompRenderWindow;
+
     qt_intf_t* m_intf = nullptr;
 
     class OurD3DCompiler;
@@ -171,9 +195,10 @@ private:
     CompositorDCompositionRenderControl* m_uiRenderControl = nullptr;
 
     //the actual window where we render
-    QWindow* m_rootWindow = nullptr;
+    DCompRenderWindow* m_renderWindow = nullptr;
 
-    QQuickWindow* m_uiWindow = nullptr;
+    //offscreen window for QML content
+    CompositorOffscreenWindow* m_uiWindow = nullptr;
     QQmlEngine* m_qmlEngine = nullptr;
     QQmlComponent* m_qmlComponent = nullptr;
     QQuickItem* m_rootItem = nullptr;


=====================================
modules/gui/qt/maininterface/compositor_x11.cpp
=====================================
@@ -25,6 +25,7 @@
 #include "interface_window_handler.hpp"
 #include "video_window_handler.hpp"
 #include "mainui.hpp"
+#include "compositor_accessibility.hpp"
 
 using namespace vlc;
 
@@ -145,6 +146,10 @@ bool CompositorX11::init()
         }
     }
 
+#if !defined(QT_NO_ACCESSIBILITY) && defined(QT5_DECLARATIVE_PRIVATE)
+    QAccessible::installFactory(&compositionAccessibleFactory);
+#endif
+
     return true;
 }
 
@@ -158,13 +163,14 @@ bool CompositorX11::makeMainInterface(MainCtx* mainCtx)
     if (!m_renderWindow->init())
         return false;
 
-    m_videoWidget = std::make_unique<DummyNativeWidget>(m_renderWindow.get());
+    m_videoWidget = std::make_unique<DummyNativeWidget>();
     // widget would normally require WindowTransparentForInput, without this
     // we end up with an invisible area within our window that grabs our mouse events.
     // But using this this causes rendering issues with some VoutDisplay
     // (xcb_render for instance) instead, we manually, set a null input region afterwards
     // see setTransparentForMouseEvent
     m_videoWidget->winId();
+    m_videoWidget->windowHandle()->setParent(m_renderWindow.get());
 
     //update manually EventMask as we don't use WindowTransparentForInput
     const uint32_t mask = XCB_CW_EVENT_MASK;
@@ -174,18 +180,16 @@ bool CompositorX11::makeMainInterface(MainCtx* mainCtx)
     setTransparentForMouseEvent(QX11Info::connection(), m_videoWidget->winId());
     m_videoWidget->show();
 
-    m_interfaceWindow = m_renderWindow->getWindow();
-
-    m_qmlView = std::make_unique<CompositorX11UISurface>(m_interfaceWindow);
+    m_qmlView = std::make_unique<CompositorX11UISurface>(m_renderWindow.get());
     m_qmlView->setFlag(Qt::WindowType::WindowTransparentForInput);
-    m_qmlView->setParent(m_interfaceWindow);
+    m_qmlView->setParent(m_renderWindow.get());
     m_qmlView->winId();
     m_qmlView->show();
 
     CompositorVideo::Flags flags = CompositorVideo::CAN_SHOW_PIP;
     if (m_renderWindow->hasAcrylic())
         flags |= CompositorVideo::HAS_ACRYLIC;
-    commonGUICreate(m_interfaceWindow, m_renderWindow.get(), m_qmlView.get(), flags);
+    commonGUICreate(m_renderWindow.get(), nullptr, m_qmlView.get(), flags);
 
     m_renderWindow->setInterfaceWindow(m_qmlView.get());
     m_renderWindow->setVideoWindow(m_videoWidget->windowHandle());
@@ -227,6 +231,8 @@ bool CompositorX11::setupVoutWindow(vlc_window_t* p_wnd, VoutDestroyCb destroyCb
     return true;
 }
 
+QWindow* CompositorX11::interfaceMainWindow() const { return m_renderWindow.get(); }
+
 QQuickItem * CompositorX11::activeFocusItem() const /* override */
 {
     return m_qmlView->activeFocusItem();


=====================================
modules/gui/qt/maininterface/compositor_x11.hpp
=====================================
@@ -49,7 +49,7 @@ public:
 
     inline Type type() const override { return X11Compositor; };
 
-    inline QWindow* interfaceMainWindow() const override { return m_interfaceWindow; };
+    QWindow* interfaceMainWindow() const override;
 
     QQuickItem * activeFocusItem() const override;
 
@@ -62,7 +62,6 @@ private slots:
     void onSurfaceSizeChanged(const QSizeF& size) override;
 
 private:
-    QWindow* m_interfaceWindow = nullptr;
     xcb_connection_t* m_conn = nullptr;
 
     std::unique_ptr<QWidget> m_videoWidget;


=====================================
modules/gui/qt/maininterface/compositor_x11_renderwindow.cpp
=====================================
@@ -23,6 +23,9 @@
 #include <QMainWindow>
 #include <QThread>
 #include <QSocketNotifier>
+#ifndef QT_NO_ACCESSIBILITY
+#include <QAccessible>
+#endif
 
 #include <xcb/composite.h>
 
@@ -80,7 +83,6 @@ void RenderTask::render(unsigned int requestId)
                                    clear, 1, &rect);
     }
 
-
     {
         QMutexLocker lock(&m_pictureLock);
         if (m_videoEmbed)
@@ -318,40 +320,23 @@ void X11DamageObserver::onEvent()
 
 //// CompositorX11RenderWindow
 
-CompositorX11RenderWindow::CompositorX11RenderWindow(qt_intf_t* p_intf, xcb_connection_t* conn, bool useCSD, QWidget* parent)
-    : QMainWindow(parent)
+CompositorX11RenderWindow::CompositorX11RenderWindow(qt_intf_t* p_intf, xcb_connection_t* conn, bool useCSD, QWindow* parent)
+    : DummyRenderWindow(parent)
     , m_intf(p_intf)
     , m_conn(conn)
 {
-    setAcceptDrops(true);
-    setAttribute(Qt::WA_NativeWindow);
-    setAttribute(Qt::WA_OpaquePaintEvent);
-    setAttribute(Qt::WA_NoSystemBackground);
-    setAttribute(Qt::WA_TranslucentBackground);
-    setAttribute(Qt::WA_MouseTracking);
-
     if (useCSD)
-        setWindowFlag(Qt::FramelessWindowHint);
-
-    m_stable = new DummyNativeWidget(this);
-    m_stable->winId();
-    setTransparentForMouseEvent(QX11Info::connection(), m_stable->winId());
-
-    setCentralWidget(m_stable);
+        setFlag(Qt::FramelessWindowHint);
 
     winId();
     show();
 
-    m_window = window()->windowHandle();
     m_wid = winId();
 }
 
 CompositorX11RenderWindow::~CompositorX11RenderWindow()
 {
     stopRendering();
-
-    removeEventFilter(this);
-    m_window->removeEventFilter(this);
 }
 
 bool CompositorX11RenderWindow::init()
@@ -377,11 +362,6 @@ bool CompositorX11RenderWindow::init()
                             blurBehindAtom, XCB_ATOM_CARDINAL, 32, 1, &val);
         m_hasAcrylic = true;
     }
-
-    //install event filters
-    installEventFilter(this);
-    m_window->installEventFilter(this);
-
     return true;
 }
 
@@ -390,7 +370,7 @@ bool CompositorX11RenderWindow::startRendering()
     assert(m_interfaceWindow);
 
     //Rendering thread
-    m_renderTask = new RenderTask(m_intf, m_conn, m_stable->effectiveWinId(), m_pictureLock);
+    m_renderTask = new RenderTask(m_intf, m_conn, m_wid, m_pictureLock);
     m_renderThread = new QThread(this);
 
     m_renderTask->moveToThread(m_renderThread);
@@ -409,7 +389,7 @@ bool CompositorX11RenderWindow::startRendering()
     //pass initial values
     m_renderTask->onInterfaceSurfaceChanged(m_interfaceClient.get());
     m_renderTask->onVideoSurfaceChanged(m_videoClient.get());
-    m_renderTask->onWindowSizeChanged(size() * devicePixelRatioF());
+    m_renderTask->onWindowSizeChanged(size() * devicePixelRatio());
     m_renderTask->onAcrylicChanged(m_hasAcrylic);
 
     //use the same thread as the rendering thread, neither tasks are blocking.
@@ -457,61 +437,33 @@ void CompositorX11RenderWindow::resetClientPixmaps()
     }
 }
 
-bool CompositorX11RenderWindow::eventFilter(QObject* obj, QEvent* event)
+void CompositorX11RenderWindow::exposeEvent(QExposeEvent* event)
 {
-    bool ret = false;
-    bool needRefresh = false;
-
-    //event on the window
-    if (obj == m_window)
-    {
-        //window may get resized without the widget knowing about it
-        if (event->type() == QEvent::Resize)
-        {
-            auto resizeEvent = static_cast<QResizeEvent*>(event);
-            if (m_interfaceWindow)
-                m_interfaceWindow->handleWindowEvent(event);
-            resetClientPixmaps();
-            emit windowSizeChanged(resizeEvent->size() * devicePixelRatioF());
-            needRefresh = true;
-        }
-    }
-    else
-    {
-        assert(obj == this);
-        if (event->type() == QEvent::Resize)
-            return false;
-
-        if (m_interfaceWindow)
-            ret =  m_interfaceWindow->handleWindowEvent(event);
+    DummyRenderWindow::exposeEvent(event);
+    resetClientPixmaps();
+    emit requestUIRefresh();
+}
 
-        switch (event->type())
-        {
-        case QEvent::Expose:
-        {
-            resetClientPixmaps();
-            needRefresh = true;
-            break;
-        }
-        case QEvent::Show:
-        {
-            resetClientPixmaps();
-            needRefresh = true;
-            emit visiblityChanged(true);
-            break;
-        }
-        case QEvent::Hide:
-            emit visiblityChanged(false);
-            break;
-        default:
-            break;
-        }
-    }
+void CompositorX11RenderWindow::resizeEvent(QResizeEvent* event)
+{
+    DummyRenderWindow::resizeEvent(event);
+    resetClientPixmaps();
+    emit windowSizeChanged(event->size() * devicePixelRatio());
+    emit requestUIRefresh();
+}
 
-    if (needRefresh)
-        emit requestUIRefresh();
+void CompositorX11RenderWindow::showEvent(QShowEvent* event)
+{
+    DummyRenderWindow::showEvent(event);
+    resetClientPixmaps();
+    emit visiblityChanged(true);
+    emit requestUIRefresh();
+}
 
-    return ret;
+void CompositorX11RenderWindow::hideEvent(QHideEvent* event)
+{
+    DummyRenderWindow::hideEvent(event);
+    emit visiblityChanged(false);
 }
 
 void CompositorX11RenderWindow::setVideoPosition(const QPoint& position)
@@ -535,7 +487,7 @@ void CompositorX11RenderWindow::setVideoSize(const QSize& size)
             m_videoClient->resetPixmap();
             m_videoClient->getPicture();
         }
-        m_videoPosition.setSize(size * devicePixelRatioF());
+        m_videoPosition.setSize(size * devicePixelRatio());
         emit videoPositionChanged(m_videoPosition);
     }
 }
@@ -560,6 +512,11 @@ void CompositorX11RenderWindow::disableVideoWindow()
     emit registerVideoWindow(0);
 }
 
+QQuickWindow* CompositorX11RenderWindow::getOffscreenWindow() const
+{
+    return m_interfaceWindow->getOffscreenWindow();
+}
+
 void CompositorX11RenderWindow::setInterfaceWindow(CompositorX11UISurface* window)
 {
     //ensure Qt x11 pending operation have been forwarded to the server


=====================================
modules/gui/qt/maininterface/compositor_x11_renderwindow.hpp
=====================================
@@ -26,7 +26,7 @@
 
 #include <QObject>
 #include <QMutex>
-#include <QMainWindow>
+#include <QWindow>
 
 #include <xcb/xcb.h>
 #include <xcb/render.h>
@@ -38,9 +38,12 @@
 #include "qt.hpp"
 
 #include "compositor_x11_utils.hpp"
+#include "compositor_common.hpp"
+#include "compositor_accessibility.hpp"
 
 class QWidget;
 class QSocketNotifier;
+class QAccessibleInterface;
 
 namespace vlc {
 
@@ -144,11 +147,11 @@ public:
     QSocketNotifier* m_socketNotifier = nullptr;
 };
 
-class CompositorX11RenderWindow : public QMainWindow
+class CompositorX11RenderWindow : public DummyRenderWindow, public AccessibleRenderWindow
 {
     Q_OBJECT
 public:
-    explicit CompositorX11RenderWindow(qt_intf_t* p_intf, xcb_connection_t* conn, bool useCSD, QWidget* parent = nullptr);
+    explicit CompositorX11RenderWindow(qt_intf_t* p_intf, xcb_connection_t* conn, bool useCSD, QWindow* parent = nullptr);
     ~CompositorX11RenderWindow();
 
     bool init();
@@ -156,13 +159,9 @@ public:
     bool startRendering();
     void stopRendering();
 
-    bool eventFilter(QObject *, QEvent *event) override;
-
     void setVideoPosition(const QPoint& position);
     void setVideoSize(const QSize& size);
 
-    inline QWindow* getWindow() const { return m_window; }
-
     inline bool hasAcrylic() const { return m_hasAcrylic; }
 
     void setVideoWindow(QWindow* window);
@@ -171,6 +170,8 @@ public:
     void enableVideoWindow();
     void disableVideoWindow();
 
+    QQuickWindow* getOffscreenWindow() const override;
+
 signals:
     void windowSizeChanged(const QSize& newSize);
     void requestUIRefresh();
@@ -179,20 +180,25 @@ signals:
     void visiblityChanged(bool visible);
     void registerVideoWindow(unsigned int xid);
 
+protected:
+    //override from QWindow
+    void exposeEvent(QExposeEvent *) override;
+    void resizeEvent(QResizeEvent *) override;
+    void showEvent(QShowEvent *) override;
+    void hideEvent(QHideEvent *) override;
+
 private:
     void resetClientPixmaps();
 
+
     qt_intf_t* m_intf = nullptr;
     xcb_connection_t* m_conn = nullptr;
 
-    QWidget* m_stable = nullptr;
-
     QThread* m_renderThread = nullptr;
     RenderTask* m_renderTask = nullptr;
     X11DamageObserver* m_damageObserver = nullptr;
     QMutex m_pictureLock;
 
-    QWindow* m_window = nullptr;
     xcb_window_t m_wid = 0;
 
     bool m_hasAcrylic = false;


=====================================
modules/gui/qt/maininterface/compositor_x11_uisurface.cpp
=====================================
@@ -21,16 +21,23 @@
 #include <QQuickWindow>
 #include <QQuickItem>
 #include <QOffscreenSurface>
+#include <QGuiApplication>
 
 #include "compositor_x11_uisurface.hpp"
+#include "compositor_common.hpp"
 
 using namespace vlc;
 
+
+
 CompositorX11UISurface::CompositorX11UISurface(QWindow* window, QScreen* screen)
     : QWindow(screen)
+    , m_renderWindow(window)
 {
     setSurfaceType(QWindow::OpenGLSurface);
 
+    m_renderWindow->installEventFilter(this);
+
     QSurfaceFormat format;
     // Qt Quick may need a depth and stencil buffer. Always make sure these are available.
     format.setDepthBufferSize(8);
@@ -50,7 +57,7 @@ CompositorX11UISurface::CompositorX11UISurface(QWindow* window, QScreen* screen)
 
     m_uiRenderControl = new CompositorX11RenderControl(window);
 
-    m_uiWindow = new QQuickWindow(m_uiRenderControl);
+    m_uiWindow = new CompositorOffscreenWindow(m_uiRenderControl);
     m_uiWindow->setDefaultAlphaBuffer(true);
     m_uiWindow->setFormat(format);
     m_uiWindow->setColor(Qt::transparent);
@@ -65,12 +72,16 @@ CompositorX11UISurface::CompositorX11UISurface(QWindow* window, QScreen* screen)
     connect(m_uiWindow, &QQuickWindow::beforeRendering, this, &CompositorX11UISurface::beforeRendering);
     connect(m_uiWindow, &QQuickWindow::afterRendering, this, &CompositorX11UISurface::afterRendering);
 
+    connect(m_uiWindow, &QQuickWindow::focusObjectChanged, this, &CompositorX11UISurface::forwardFocusObjectChanged);
+
     connect(m_uiRenderControl, &QQuickRenderControl::renderRequested, this, &CompositorX11UISurface::requestUpdate);
     connect(m_uiRenderControl, &QQuickRenderControl::sceneChanged, this, &CompositorX11UISurface::requestUpdate);
 }
 
 CompositorX11UISurface::~CompositorX11UISurface()
 {
+    m_renderWindow->removeEventFilter(this);
+
     auto surface = new QOffscreenSurface();
     surface->setFormat(m_context->format());
     surface->create();
@@ -109,6 +120,11 @@ QQuickItem * CompositorX11UISurface::activeFocusItem() const /* override */
     return m_uiWindow->activeFocusItem();
 }
 
+QQuickWindow* CompositorX11UISurface::getOffscreenWindow() const
+{
+    return m_uiWindow;
+}
+
 void CompositorX11UISurface::createFbo()
 {
     //write to the immediate context
@@ -191,7 +207,7 @@ static void remapInputMethodQueryEvent(QObject *object, QInputMethodQueryEvent *
     }
 }
 
-bool CompositorX11UISurface::handleWindowEvent(QEvent *event)
+bool CompositorX11UISurface::eventFilter(QObject*, QEvent *event)
 {
     switch (event->type())
     {
@@ -230,6 +246,17 @@ bool CompositorX11UISurface::handleWindowEvent(QEvent *event)
         return ret;
     }
 
+    case QEvent::FocusAboutToChange:
+    case QEvent::FocusIn:
+    case QEvent::FocusOut:
+        return QCoreApplication::sendEvent(m_uiWindow, event);
+
+    case QEvent::Show:
+        m_uiWindow->setPseudoVisible(true);
+        break;
+    case QEvent::Hide:
+        m_uiWindow->setPseudoVisible(false);
+        break;
     case QEvent::InputMethod:
         return QCoreApplication::sendEvent(m_uiWindow->focusObject(), event);
 
@@ -321,6 +348,11 @@ void CompositorX11UISurface::handleScreenChange()
     requestUpdate();
 }
 
+void CompositorX11UISurface::forwardFocusObjectChanged(QObject* object)
+{
+    m_renderWindow->focusObjectChanged(object);
+}
+
 QWindow* CompositorX11RenderControl::renderWindow(QPoint* offset)
 {
     if (offset)


=====================================
modules/gui/qt/maininterface/compositor_x11_uisurface.hpp
=====================================
@@ -19,6 +19,7 @@
 #define COMPOSITOR_X11_UISURFACE_HPP
 
 #include <QWindow>
+#include <QQuickWindow>
 #include <QQuickRenderControl>
 #include "compositor.hpp"
 
@@ -26,9 +27,12 @@ class QQuickWindow;
 class QQmlEngine;
 class QQmlComponent;
 class QQuickItem;
+class QQuickRenderControl;
 
 namespace vlc {
 
+class CompositorOffscreenWindow;
+
 class CompositorX11RenderControl : public QQuickRenderControl {
     Q_OBJECT
 public:
@@ -37,6 +41,7 @@ public:
         , m_window(window)
     {}
 
+
     QWindow *renderWindow(QPoint * offset) override;
 
 private:
@@ -60,6 +65,8 @@ public:
 
     QQuickItem * activeFocusItem() const override;
 
+    QQuickWindow* getOffscreenWindow() const;
+
 signals:
     void beforeRendering();
     void afterRendering();
@@ -67,12 +74,14 @@ signals:
     void updated();
 
 protected:
+    bool eventFilter(QObject* object, QEvent *event) override;
+
     bool event(QEvent *event) override;
 
     void resizeEvent(QResizeEvent *) override;
     void exposeEvent(QExposeEvent *) override;
     void handleScreenChange();
-
+    void forwardFocusObjectChanged(QObject* focusObject);
 
     void updateSizes();
 
@@ -83,8 +92,9 @@ protected:
 private:
     QQuickItem* m_rootItem = nullptr;
     QOpenGLContext *m_context = nullptr;
-    QQuickWindow* m_uiWindow = nullptr;
+    CompositorOffscreenWindow* m_uiWindow = nullptr;
     QQmlEngine* m_qmlEngine = nullptr;
+    QWindow* m_renderWindow = nullptr;
     CompositorX11RenderControl* m_uiRenderControl = nullptr;
 
     QSize m_onscreenSize;


=====================================
modules/gui/qt/meson.build
=====================================
@@ -16,6 +16,7 @@ qt5_dep = dependency('qt5',
         'Core', 'Gui', 'Widgets', 'Svg', 'Qml',
         'Quick', 'QuickWidgets', 'QuickControls2',
         ],
+    private_headers: true,
     required: get_option('qt'))
 
 moc_headers = files(
@@ -64,6 +65,7 @@ moc_headers = files(
     'dialogs/playlists/playlists.hpp',
     'dialogs/vlm/vlm.hpp',
     'maininterface/compositor.hpp',
+    'maininterface/compositor_common.hpp',
     'maininterface/compositor_dummy.hpp',
     'maininterface/interface_window_handler.hpp',
     'maininterface/mainctx.hpp',
@@ -271,6 +273,10 @@ some_sources = files(
     'dialogs/playlists/playlists.hpp',
     'maininterface/compositor.hpp',
     'maininterface/compositor.cpp',
+    'maininterface/compositor_common.hpp',
+    'maininterface/compositor_common.cpp',
+    'maininterface/compositor_accessibility.hpp',
+    'maininterface/compositor_accessibility.cpp',
     'maininterface/compositor_dummy.hpp',
     'maininterface/compositor_dummy.cpp',
     'maininterface/interface_window_handler.cpp',
@@ -637,6 +643,12 @@ if qt5_dep.found()
         qt_extra_flags += '-DQT_QML_DEBUG'
     endif
 
+    #check private headers
+    if cpp.has_header('private/qquickitem_p.h', dependencies: qt5_dep) \
+      and cpp.has_header('private/qquickwindow_p.h', dependencies: qt5_dep)
+        qt_extra_flags += '-DQT5_DECLARATIVE_PRIVATE'
+    endif
+
     if host_system == 'windows'
         qt_cppargs += libcom_cppflags
         qt_extra_flags += '-DQPNI_HEADER=<' + qt5_dep.version() + '/QtGui/qpa/qplatformnativeinterface.h>'



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e7d0535a5d270efb16cfb6b34e923c8f88a37e47...9d8fa31838a771e1502cf2b05667fdf1eef87a37

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e7d0535a5d270efb16cfb6b34e923c8f88a37e47...9d8fa31838a771e1502cf2b05667fdf1eef87a37
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list