mirror of https://code.videolan.org/videolan/vlc
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:
parent
ad3c0ba11a
commit
05738f575b
|
@ -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 += \
|
||||
|
|
|
@ -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;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue