Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/gui/qt/maininterface/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 11 kB image not shown  

Quelle  compositor_x11.cpp   Sprache: C

 

/*****************************************************************************
 * Copyright (C) 2020 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 <QScreen>

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_window.h>
#include <vlc_cxx_helpers.hpp>

#include "compositor_x11.hpp"
#include "compositor_x11_renderwindow.hpp"
#include "compositor_x11_uisurface.hpp"
#include "mainctx.hpp"
#include "interface_window_handler.hpp"
#include "video_window_handler.hpp"
#include "mainui.hpp"
#include "compositor_accessibility.hpp"

#ifdef QT_DECLARATIVE_PRIVATE
#include <private/qquickitem_p.h>
#include <private/qquickwindow_p.h>
#endif

#ifndef X_DISPLAY_MISSING
#include <X11/Xlib.h>
#endif

using namespace vlc;

int CompositorX11::windowEnable(const vlc_window_cfg_t *)
{
    commonWindowEnable();
    m_renderWindow->enableVideoWindow();
    return VLC_SUCCESS;
}

void CompositorX11::windowDisable()
{
    m_renderWindow->disableVideoWindow();
    commonWindowDisable();
}

CompositorX11::CompositorX11(qt_intf_t *p_intf, QObject *parent)
    : CompositorVideo(p_intf, parent)
{
}

CompositorX11::~CompositorX11()
{
    if (m_conn)
        xcb_disconnect(m_conn);
}

static bool checkExtensionPresent(qt_intf_t* intf, xcb_connection_t *conn, const char* extension)
{
    bool ret = queryExtension(conn, extension, nullptr, nullptr);
    if (! ret)
        msg_Warn(intf, "X11 extension %s is missing", extension);
    return ret;
}

#define REGISTER_XCB_EXTENSION(c, extension, minor, major) \
    do { \
        xcb_ ## extension  ##_query_version_cookie_t cookie = xcb_## extension  ##_query_version(c, minor, major); \
        xcb_generic_error_t* error = nullptr; \
        auto reply = wrap_cptr(xcb_## extension  ##_query_version_reply(c, cookie, &error)); \
        if (error) { \
            msg_Warn(m_intf, "X11 extension %s is too old", #extension); \
            free(error); \
            return false; \
        } \
    } while(0)


bool CompositorX11::init()
{
    if (!qGuiApp->nativeInterface<QNativeInterface::QX11Application>())
    {
        msg_Info(m_intf, "not running an X11 platform");
        return false;
    }

    const QString& sceneGraphBackend = qEnvironmentVariable("QT_QUICK_BACKEND");
    if (!sceneGraphBackend.isEmpty() /* if empty, RHI is used */ &&
        sceneGraphBackend != QLatin1String("rhi") &&
        sceneGraphBackend != QLatin1String("software"))
    {
        // No RHI means no OpenGL, the graphics API check below is
        // only relevant when RHI is in use. If QT_QUICK_BACKEND is
        // set to software or openvg, then `QQuickWindow::graphicsApi()`
        // might still report OpenGL until the scene graph is initialized.
        // Unlike `QQuickWindow::graphicsApi()`, `sceneGraphBackend()`
        // is only valid after the window is constructed, so instead
        // of using `QQuickWindow::sceneGraphBackend()`, simply probe
        // the environment variable.
        return false;
    }

    const auto graphicsApi = QQuickWindow::graphicsApi();
    if (graphicsApi != QSGRendererInterface::OpenGL &&
        graphicsApi != QSGRendererInterface::Software)
    {
        msg_Warn(m_intf, "CompositorX11: Only software mode and rhi opengl are supported!");
        return false;
    }

    //open a separated X11 connection from Qt to be able to receive
    //damage events independently from Qt (even when Qt's main loop is stalled)
    m_conn = xcb_connect(nullptr, nullptr);
    if (xcb_connection_has_error(m_conn) != 0)
    {
        msg_Warn(m_intf, "can't open X11 connection");
        return false;
    }

    //check X11 extensions
    if (!checkExtensionPresent(m_intf, m_conn, "DAMAGE"))
        return false;
    REGISTER_XCB_EXTENSION(m_conn, damage, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION);

    if (!checkExtensionPresent(m_intf, m_conn, "RENDER"))
        return false;
    //0.11 required for Blend mode operators
    static_assert (XCB_RENDER_MAJOR_VERSION == 0 && XCB_RENDER_MINOR_VERSION >= 11,
            "X11 Render version is too old, 0.11+ is required");
    REGISTER_XCB_EXTENSION(m_conn, render, XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MINOR_VERSION);

    if (!checkExtensionPresent(m_intf, m_conn, "Composite"))
        return false;
    //0.2 is required for NameWindowPixmap
    static_assert (XCB_COMPOSITE_MAJOR_VERSION == 0 && XCB_COMPOSITE_MINOR_VERSION >= 2,
            "X11 Composite version is too old, 0.2+ is required");
    REGISTER_XCB_EXTENSION(m_conn, composite, XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MINOR_VERSION);

    if (!checkExtensionPresent(m_intf, m_conn, "XFIXES"))
        return false;
    //2.x is required for SetWindowShapeRegion
    static_assert (XCB_XFIXES_MAJOR_VERSION >= 2,
            "X11 Fixes version is too old, 2.0+ is required");
    REGISTER_XCB_EXTENSION(m_conn, xfixes, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);

    // check whether we're running under "XWAYLAND"
    auto screens = qApp->screens();
    bool isXWayland = std::any_of(screens.begin(), screens.end(), [](QScreen* screen){
        return screen->name().startsWith("XWAYLAND");
    });

    if (isXWayland)
    {
        // if the X11 server is XWayland, test if it is a broken version
        const xcb_setup_t* setup = xcb_get_setup(m_conn);

        if (setup == nullptr)
        {
            msg_Info(m_intf, "error checking for XWayland version");
            return false;
        }

        if (setup->release_number < 12100000u)
        {
            msg_Info(m_intf, "running a broken XWayland version, disabling X11 composition");
            return false;
        }
    }

#if !defined(QT_NO_ACCESSIBILITY) && defined(QT_DECLARATIVE_PRIVATE)
   QAccessible::installFactory(&compositionAccessibleFactory);
#endif

    return true;
}

bool CompositorX11::makeMainInterface(MainCtx* mainCtx, std::function<void (QQuickWindow *)> aboutToShowQuickWindowCallback)
{
    m_mainCtx = mainCtx;

    m_renderWindow = std::make_unique<vlc::CompositorX11RenderWindow>(m_intf, m_conn);
    if (!m_renderWindow->init())
        return false;

    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;
    const uint32_t values = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY
        | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE;

    const auto connection =  qGuiApp->nativeInterface<QNativeInterface::QX11Application>()->connection();

    xcb_change_window_attributes(connection, m_videoWidget->winId(), mask, &values);
    setTransparentForMouseEvent(connection, m_videoWidget->winId());
    m_videoWidget->setVisible(true);

    connect(m_mainCtx, &MainCtx::hasAcrylicSurfaceChanged, m_renderWindow.get(), &CompositorX11RenderWindow::setAcrylic);

    m_qmlView = std::make_unique<CompositorX11UISurface>(m_renderWindow.get());

    m_qmlView->setFlag(Qt::WindowType::WindowTransparentForInput);
    m_qmlView->setParent(m_renderWindow.get());
    m_qmlView->create();
    CompositorVideo::Flags flags = CompositorVideo::CAN_SHOW_PIP | HAS_ACRYLIC;
    if (m_renderWindow->supportExtendedFrame())
        flags |= CompositorVideo::HAS_EXTENDED_FRAME;
    assert(m_qmlView->getOffscreenWindow());
    m_qmlView->getOffscreenWindow()->create();
    if (!commonGUICreate(m_renderWindow.get(), m_qmlView.get(), flags))
        return false;

    if (aboutToShowQuickWindowCallback)
        aboutToShowQuickWindowCallback(m_qmlView->getOffscreenWindow());

    m_qmlView->setVisible(true);

    if (m_mainCtx->hasAcrylicSurface())
        m_renderWindow->m_hasAcrylic = true;

    m_renderWindow->setInterfaceWindow(m_qmlView.get());
    m_renderWindow->setVideoWindow(m_videoWidget->windowHandle());

    m_renderWindow->startRendering();

    return true;
}

void CompositorX11::destroyMainInterface()
{
    commonIntfDestroy();
    m_videoWidget.reset();
    m_renderWindow.reset();
}

void CompositorX11::unloadGUI()
{
    m_renderWindow->stopRendering();
    m_qmlView.reset();
    commonGUIDestroy();
}

void CompositorX11::onSurfacePositionChanged(const QPointF& position)
{
    m_pendingPosition = QPoint{static_cast<int>(position.x()), static_cast<int>(position.y())};
}

void CompositorX11::onSurfaceSizeChanged(const QSizeF& size)
{
    const QSizeF area = (size / m_videoWidget->window()->devicePixelRatioF());
    m_pendingSize = QSize{static_cast<int>(std::ceil(area.width())), static_cast<int>(std::ceil(area.height()))};
}

bool CompositorX11::setupVoutWindow(vlc_window_t* p_wnd, VoutDestroyCb destroyCb)
{
    if (m_wnd)
        return false;

    p_wnd->type = VLC_WINDOW_TYPE_XID;
    p_wnd->handle.xid = m_videoWidget->winId();
#ifndef X_DISPLAY_MISSING
    assert(qGuiApp);
    const auto x11App = qGuiApp->nativeInterface<QNativeInterface::QX11Application>();
    assert(x11App); // already checked in `init()`
    assert(x11App->display());
    p_wnd->display.x11 = XDisplayString(x11App->display());
#endif

    commonSetupVoutWindow(p_wnd, destroyCb);
    return true;
}

QWindow* CompositorX11::interfaceMainWindow() const { return m_renderWindow.get(); }

QQuickWindow *CompositorX11::quickWindow() const
{
    assert(m_qmlView);
    return m_qmlView->getOffscreenWindow();
}

QQuickItem * CompositorX11::activeFocusItem() const /* override */
{
    return m_qmlView->activeFocusItem();
}

void CompositorX11::commitSurface()
{
    if (m_renderWindow)
        m_renderWindow->setVideoGeometry(m_pendingPosition, m_pendingSize);
}

///////// DummyNativeWidget

DummyNativeWidget::DummyNativeWidget(QWidget* parent, Qt::WindowFlags f)
    : QWidget(parent, f)
{
    setAttribute(Qt::WA_NativeWindow, true);
    setAttribute(Qt::WA_OpaquePaintEvent, true);
    setAttribute(Qt::WA_PaintOnScreen, true);
    setAttribute(Qt::WA_MouseTracking, true);
    setAttribute(Qt::WA_TranslucentBackground, false);
    QWindow* w =  window()->windowHandle();
    assert(w);
    /*
     * force the window not to have an alpha channel, the  parent window
     * may have an alpha channel and child widget would inhertit the format
     * even if we set Qt::WA_TranslucentBackground to false. having an alpha
     * in this surface would lead to the video begin semi-tranparent.
     */

    QSurfaceFormat format = w->format();
    format.setAlphaBufferSize(0);
    w->setFormat(format);
}

DummyNativeWidget::~DummyNativeWidget()
{

}

QPaintEngine* DummyNativeWidget::paintEngine() const
{
    return nullptr;
}

Messung
CHZG
849810094

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.