qt: provide video integration for windows 7

this class is also used on windows when D3D isn't supported, because the dummy
 compositor uses QQuickWidget which requires opengl offscreen rendering (trough
 angle on windows)
This commit is contained in:
Pierre Lamot 2020-06-18 16:36:36 +02:00
parent ad3c0ba11a
commit 05738f575b
5 changed files with 425 additions and 8 deletions

View File

@ -224,7 +224,9 @@ libqt_plugin_la_SOURCES = \
if HAVE_WIN32
libqt_plugin_la_SOURCES += \
gui/qt/maininterface/main_interface_win32.cpp \
gui/qt/maininterface/main_interface_win32.hpp
gui/qt/maininterface/main_interface_win32.hpp \
gui/qt/maininterface/compositor_win7.cpp \
gui/qt/maininterface/compositor_win7.hpp
if HAVE_DCOMP
libqt_plugin_la_SOURCES += \
@ -343,7 +345,8 @@ nodist_libqt_plugin_la_SOURCES = \
gui/qt/widgets/native/searchlineedit.moc.cpp
if HAVE_WIN32
nodist_libqt_plugin_la_SOURCES += gui/qt/maininterface/main_interface_win32.moc.cpp
nodist_libqt_plugin_la_SOURCES += gui/qt/maininterface/main_interface_win32.moc.cpp \
gui/qt/maininterface/compositor_win7.moc.cpp
if HAVE_DCOMP
nodist_libqt_plugin_la_SOURCES += \

View File

@ -23,6 +23,7 @@
#ifdef HAVE_DCOMP_H
# include "compositor_dcomp.hpp"
#endif
# include "compositor_win7.hpp"
#endif
namespace vlc {
@ -37,9 +38,14 @@ Compositor* Compositor::createCompositor(intf_thread_t *p_intf)
ret = dcomp_compositor->init();
if (ret)
return dcomp_compositor;
else
delete dcomp_compositor;
delete dcomp_compositor;
msg_Dbg(p_intf, "failed to create DirectComposition backend, use fallback");
#endif
CompositorWin7* win7_compositor = new CompositorWin7(p_intf);
if (win7_compositor->init())
return win7_compositor;
delete win7_compositor;
msg_Dbg(p_intf, "failed to create Win7 compositor backend, use fallback");
#endif
return new CompositorDummy(p_intf);
}

View File

@ -34,18 +34,18 @@ class CompositorDummy : public QObject, public Compositor
Q_OBJECT
public:
CompositorDummy(intf_thread_t *p_intf, QObject* parent = nullptr);
~CompositorDummy() = default;
virtual ~CompositorDummy() = default;
MainInterface *makeMainInterface() override;
virtual MainInterface *makeMainInterface() override;
virtual void destroyMainInterface() override;
bool setupVoutWindow(vout_window_t *p_wnd) override;
private:
protected:
intf_thread_t *m_intf;
MainInterface* m_rootWindow;
MainInterface* m_rootWindow = nullptr;
};
}

View File

@ -0,0 +1,323 @@
/*****************************************************************************
* 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 "compositor_win7.hpp"
#include "main_interface_win32.hpp"
#include "mainui.hpp"
#include <d3d11.h>
#include <dwmapi.h>
#include <QLibrary>
using namespace vlc;
int CompositorWin7::window_enable(struct vout_window_t * p_wnd, const vout_window_cfg_t *)
{
CompositorWin7* that = static_cast<CompositorWin7*>(p_wnd->sys);
msg_Dbg(that->m_intf, "window_enable");
that->m_qmlVideoSurfaceProvider->enable(p_wnd);
return VLC_SUCCESS;
}
void CompositorWin7::window_disable(struct vout_window_t * p_wnd)
{
CompositorWin7* that = static_cast<CompositorWin7*>(p_wnd->sys);
that->m_qmlVideoSurfaceProvider->disable();
that->m_videoWindowHandler->disable();
msg_Dbg(that->m_intf, "window_disable");
}
void CompositorWin7::window_resize(struct vout_window_t * p_wnd, unsigned width, unsigned height)
{
CompositorWin7* that = static_cast<CompositorWin7*>(p_wnd->sys);
msg_Dbg(that->m_intf, "window_resize %ux%u", width, height);
that->m_videoWindowHandler->requestResizeVideo(width, height);
}
void CompositorWin7::window_destroy(struct vout_window_t * p_wnd)
{
CompositorWin7* that = static_cast<CompositorWin7*>(p_wnd->sys);
msg_Dbg(that->m_intf, "window_destroy");
}
void CompositorWin7::window_set_state(struct vout_window_t * p_wnd, unsigned state)
{
CompositorWin7* that = static_cast<CompositorWin7*>(p_wnd->sys);
msg_Dbg(that->m_intf, "window_set_state");
that->m_videoWindowHandler->requestVideoState(static_cast<vout_window_state>(state));
}
void CompositorWin7::window_unset_fullscreen(struct vout_window_t * p_wnd)
{
CompositorWin7* that = static_cast<CompositorWin7*>(p_wnd->sys);
msg_Dbg(that->m_intf, "window_unset_fullscreen");
that->m_videoWindowHandler->requestVideoWindowed();
}
void CompositorWin7::window_set_fullscreen(struct vout_window_t * p_wnd, const char *id)
{
CompositorWin7* that = static_cast<CompositorWin7*>(p_wnd->sys);
msg_Dbg(that->m_intf, "window_set_fullscreen");
that->m_videoWindowHandler->requestVideoFullScreen(id);
}
CompositorWin7::CompositorWin7(intf_thread_t *p_intf, QObject* parent)
: CompositorDummy(p_intf, parent)
{
}
CompositorWin7::~CompositorWin7()
{
if (m_taskbarWidget)
qApp->removeNativeEventFilter(m_taskbarWidget);
if (m_nativeEventFilter)
qApp->removeNativeEventFilter(m_nativeEventFilter);
if (m_stable)
delete m_stable;
}
bool CompositorWin7::init()
{
//check whether D3DCompiler is available. whitout it Angle won't work
QLibrary d3dCompilerDll;
for (int i = 47; i > 41; --i)
{
d3dCompilerDll.setFileName(QString("D3DCOMPILER_%1.dll").arg(i));
if (d3dCompilerDll.load())
break;
}
D3D_FEATURE_LEVEL requestedFeatureLevels[] = {
D3D_FEATURE_LEVEL_9_1,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
};
HRESULT hr = D3D11CreateDevice(
nullptr, // Adapter
D3D_DRIVER_TYPE_HARDWARE,
nullptr, // Module
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
requestedFeatureLevels,
ARRAY_SIZE(requestedFeatureLevels),
D3D11_SDK_VERSION,
nullptr, //D3D device
nullptr, // Actual feature level
nullptr //D3D context
);
//no hw acceleration, manually select the software backend
//otherwise Qt will load angle and fail.
if (!d3dCompilerDll.isLoaded() || FAILED(hr))
{
msg_Info(m_intf, "no D3D support, use software backend");
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
}
return true;
}
MainInterface* CompositorWin7::makeMainInterface()
{
//Tool flag needs to be passed in the window constructor otherwise the
//window will still appears int the taskbar
MainInterfaceWin32* rootWindowW32 = new MainInterfaceWin32(m_intf, nullptr, Qt::Tool | Qt::FramelessWindowHint );
m_rootWindow = rootWindowW32;
//m_rootWindow6>show() is not called on purpose
/*
* m_stable is not attached to the main interface because dialogs are attached to the mainInterface
* and showing them would raise the video widget above the interface
*/
m_stable = new QWidget(nullptr, Qt::Tool | Qt::FramelessWindowHint);
m_stable->setContextMenuPolicy( Qt::PreventContextMenu );
QPalette plt = m_rootWindow->palette();
plt.setColor( QPalette::Window, Qt::black );
m_stable->setPalette( plt );
m_stable->setAutoFillBackground(true);
/* Force the widget to be native so that it gets a winId() */
m_stable->setAttribute( Qt::WA_NativeWindow, true );
m_stable->setAttribute( Qt::WA_PaintOnScreen, true );
m_stable->setMouseTracking( true );
m_stable->setWindowFlags( Qt::Tool | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus );
m_stable->setAttribute( Qt::WA_ShowWithoutActivating );
m_stable->show();
m_videoWindowHWND = (HWND)m_stable->winId();
BOOL excluseFromPeek = TRUE;
DwmSetWindowAttribute(m_videoWindowHWND, DWMWA_EXCLUDED_FROM_PEEK, &excluseFromPeek, sizeof(excluseFromPeek));
DwmSetWindowAttribute(m_videoWindowHWND, DWMWA_DISALLOW_PEEK, &excluseFromPeek, sizeof(excluseFromPeek));
m_qmlVideoSurfaceProvider = std::make_unique<VideoSurfaceProvider>();
m_rootWindow->setVideoSurfaceProvider(m_qmlVideoSurfaceProvider.get());
m_qmlView = std::make_unique<QQuickView>();
m_qmlView->setResizeMode(QQuickView::SizeRootObjectToView);
m_qmlView->setClearBeforeRendering(true);
m_qmlView->setColor(QColor(Qt::transparent));
m_qmlView->setGeometry(m_rootWindow->geometry());
m_qmlView->setMinimumSize( m_rootWindow->minimumSize() );
m_qmlView->installEventFilter(this);
Win7NativeEventFilter* m_nativeEventFilter = new Win7NativeEventFilter(this);
qApp->installNativeEventFilter(m_nativeEventFilter);
connect(m_nativeEventFilter, &Win7NativeEventFilter::windowStyleChanged,
this, &CompositorWin7::resetVideoZOrder);
m_qmlView->show();
m_qmlWindowHWND = (HWND)m_qmlView->winId();
m_videoWindowHandler = std::make_unique<VideoWindowHandler>(m_intf, m_rootWindow);
m_videoWindowHandler->setWindow( m_qmlView.get() );
new InterfaceWindowHandlerWin32(m_intf, m_rootWindow, m_qmlView.get(), m_qmlView.get());
m_taskbarWidget = new WinTaskbarWidget(m_intf, m_qmlView.get(), this);
qApp->installNativeEventFilter(m_taskbarWidget);
MainUI* m_ui = new MainUI(m_intf, m_rootWindow, this);
m_ui->setup(m_qmlView->engine());
m_qmlView->setContent(QUrl(), m_ui->getComponent(), m_ui->createRootItem());
connect(m_rootWindow, &MainInterface::windowTitleChanged,
m_qmlView.get(), &QQuickView::setTitle);
connect(m_rootWindow, &MainInterface::windowIconChanged,
m_qmlView.get(), &QQuickView::setIcon);
return m_rootWindow;
}
bool CompositorWin7::setupVoutWindow(vout_window_t *p_wnd)
{
BOOL isCompositionEnabled;
HRESULT hr = DwmIsCompositionEnabled(&isCompositionEnabled);
//composition is disabled, video can't be seen through the interface,
//so we fallback to a separate window.
if (FAILED(hr) || !isCompositionEnabled)
return false;
static const struct vout_window_operations ops = {
CompositorWin7::window_enable,
CompositorWin7::window_disable,
CompositorWin7::window_resize,
CompositorWin7::window_destroy,
CompositorWin7::window_set_state,
CompositorWin7::window_unset_fullscreen,
CompositorWin7::window_set_fullscreen,
nullptr, //window_set_title
};
p_wnd->sys = this;
p_wnd->type = VOUT_WINDOW_TYPE_HWND;
p_wnd->handle.hwnd = (HWND)m_stable->winId();
p_wnd->display.x11 = nullptr;
p_wnd->ops = &ops;
p_wnd->info.has_double_click = true;
return true;
}
bool CompositorWin7::eventFilter(QObject*, QEvent* ev)
{
switch (ev->type())
{
case QEvent::Close:
m_rootWindow->close();
break;
case QEvent::Move:
case QEvent::Resize:
case QEvent::ApplicationStateChange:
m_stable->setGeometry(m_qmlView->geometry());
resetVideoZOrder();
break;
case QEvent::WindowStateChange:
if (m_qmlView->windowStates() & Qt::WindowMinimized)
m_stable->hide();
else
{
m_stable->show();
m_stable->setGeometry(m_qmlView->geometry());
resetVideoZOrder();
}
break;
case QEvent::FocusIn:
resetVideoZOrder();
break;
case QEvent::Show:
m_stable->show();
resetVideoZOrder();
break;
case QEvent::Hide:
m_stable->hide();
break;
default:
break;
}
return false;
}
void CompositorWin7::resetVideoZOrder()
{
//Place the video wdiget right behind the interface
HWND bottomHWND = m_qmlWindowHWND;
HWND currentHWND = bottomHWND;
while (currentHWND != nullptr)
{
bottomHWND = currentHWND;
currentHWND = GetWindow(bottomHWND, GW_OWNER);
}
SetWindowPos(
m_videoWindowHWND,
bottomHWND,
0,0,0,0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE
);
}
Win7NativeEventFilter::Win7NativeEventFilter(QObject* parent)
: QObject(parent)
{
}
//parse native events that are not reported by Qt
bool Win7NativeEventFilter::nativeEventFilter(const QByteArray&, void* message, long*)
{
MSG * msg = static_cast<MSG*>( message );
switch( msg->message )
{
//style like "always on top" changed
case WM_STYLECHANGED:
emit windowStyleChanged();
break;
}
return false;
}

View File

@ -0,0 +1,85 @@
/*****************************************************************************
* 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.
*****************************************************************************/
#ifndef COMPOSITORDUMMYWIN32_H
#define COMPOSITORDUMMYWIN32_H
#include "compositor_dummy.hpp"
#include "videosurface.hpp"
#include "video_window_handler.hpp"
#include <QAbstractNativeEventFilter>
#include <memory>
class WinTaskbarWidget;
namespace vlc {
class Win7NativeEventFilter : public QObject, public QAbstractNativeEventFilter {
Q_OBJECT
public:
Win7NativeEventFilter( QObject* parent = nullptr );
bool nativeEventFilter(const QByteArray &, void *message, long* /* result */);
signals:
void windowStyleChanged();
};
class CompositorWin7 : public CompositorDummy
{
Q_OBJECT
public:
CompositorWin7(intf_thread_t *p_intf, QObject* parent = nullptr);
virtual ~CompositorWin7();
bool init();
virtual MainInterface *makeMainInterface() override;
virtual bool setupVoutWindow(vout_window_t*) override;
protected:
bool eventFilter(QObject *obj, QEvent *ev) override;
private:
static int window_enable(struct vout_window_t *, const vout_window_cfg_t *);
static void window_disable(struct vout_window_t *);
static void window_resize(struct vout_window_t *, unsigned width, unsigned height);
static void window_destroy(struct vout_window_t *);
static void window_set_state(struct vout_window_t *, unsigned state);
static void window_unset_fullscreen(struct vout_window_t *);
static void window_set_fullscreen(struct vout_window_t *, const char *id);
private slots:
void resetVideoZOrder();
private:
QWidget* m_stable = nullptr;
std::unique_ptr<QQuickView> m_qmlView;
std::unique_ptr<VideoWindowHandler> m_videoWindowHandler;
std::unique_ptr<VideoSurfaceProvider> m_qmlVideoSurfaceProvider;
WinTaskbarWidget* m_taskbarWidget = nullptr;
Win7NativeEventFilter* m_nativeEventFilter = nullptr;
HWND m_qmlWindowHWND = nullptr;
HWND m_videoWindowHWND = nullptr;
};
}
#endif // COMPOSITORDUMMYWIN32_H