Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC
Commits: 87cb513e by Prince Gupta at 2021-09-12T12:46:25+00:00 qt/MainInterface: implement acrylic surface notifiers - - - - - 034edad6 by Steve Lhomme at 2021-09-12T12:46:25+00:00 contrib: pthreads: patch dcomp.h from mingw64 to add gaussian effect - - - - - b74b0758 by Prince Gupta at 2021-09-12T12:46:25+00:00 qt/compositor_dcomp: force Win 8.1 compilation To allow use of IDCompositionGaussianBlurEffect and others - - - - - 606d8cfa by Prince Gupta at 2021-09-12T12:46:25+00:00 qt/compositor_dcomp: allow adding visual from outside - - - - - c6afb90a by Prince Gupta at 2021-09-12T12:46:25+00:00 qt/compositor_dcomp: implement acrylicsurface - - - - - dcd3d543 by Prince Gupta at 2021-09-12T12:46:25+00:00 qml: implement AcrylicBackground - - - - - ca242d7b by Prince Gupta at 2021-09-12T12:46:25+00:00 qml/BannerSource: use AcrylicBackground - - - - - 2d6c4156 by Prince Gupta at 2021-09-12T12:46:25+00:00 qml/MusicArtistsAlbums: use AcrylicBackground for list - - - - - b605fd25 by Prince Gupta at 2021-09-12T12:46:25+00:00 qml/PlaylistListView: use AcrylicBackground - - - - - 16 changed files: - + contrib/src/pthreads/0001-dcomp.h-add-some-missing-interfaces.patch - contrib/src/pthreads/rules.mak - modules/gui/qt/Makefile.am - modules/gui/qt/maininterface/compositor_dcomp.cpp - modules/gui/qt/maininterface/compositor_dcomp.hpp - + modules/gui/qt/maininterface/compositor_dcomp_acrylicsurface.cpp - + modules/gui/qt/maininterface/compositor_dcomp_acrylicsurface.hpp - modules/gui/qt/maininterface/compositor_dcomp_uisurface.hpp - modules/gui/qt/maininterface/main_interface.cpp - modules/gui/qt/maininterface/main_interface.hpp - modules/gui/qt/maininterface/qml/BannerSources.qml - modules/gui/qt/medialibrary/qml/MusicArtistsAlbums.qml - modules/gui/qt/player/qml/Player.qml - modules/gui/qt/playlist/qml/PlaylistListView.qml - modules/gui/qt/vlc.qrc - + modules/gui/qt/widgets/qml/AcrylicBackground.qml Changes: ===================================== contrib/src/pthreads/0001-dcomp.h-add-some-missing-interfaces.patch ===================================== @@ -0,0 +1,111 @@ +From 9de58105bbe6fb870c746d3f5c4ed97d91ba1b7c Mon Sep 17 00:00:00 2001 +From: Steve Lhomme <[email protected]> +Date: Tue, 7 Sep 2021 14:36:16 +0200 +Subject: [PATCH] dcomp.h: add some missing interfaces + +* IDCompositionFilterEffect: https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nn-dcomp-idcompositionfiltereffect +* IDCompositionSaturationEffect: https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nn-dcomp-idcompositionsaturationeffect +* IDCompositionGaussianBlurEffect: https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nn-dcomp-idcompositiongaussianblureffect +* IDCompositionDevice3: https://docs.microsoft.com/en-us/windows/win32/api/dcomp/nn-dcomp-idcompositiondevice3 + +The order of methods can be found from +https://github.com/terrafx/terrafx.interop.windows/tree/main/sources/Interop/Windows/um/dcomp + +As for other IDCompositionEffect interfaces, some methods are inverted for MSVC +compilation in C++ (which is odd). + +Co-authored-by: Prince Gupta <[email protected]> +--- + mingw-w64-headers/include/dcomp.h | 74 +++++++++++++++++++++++++++++++ + 1 file changed, 74 insertions(+) + +diff --git a/mingw-w64-headers/include/dcomp.h b/mingw-w64-headers/include/dcomp.h +index 58f4b8466..7f124ca99 100644 +--- a/mingw-w64-headers/include/dcomp.h ++++ b/mingw-w64-headers/include/dcomp.h +@@ -524,8 +524,82 @@ __CRT_UUID_DECL(IDCompositionVisualDebug,0xfed2b808,0x5eb4,0x43a0,0xae,0xa3,0x35 + #endif + + ++#undef INTERFACE ++#define INTERFACE IDCompositionFilterEffect ++DECLARE_INTERFACE_IID_(IDCompositionFilterEffect, IDCompositionEffect, "30C421D5-8CB2-4E9F-B133-37BE270D4AC2") ++{ ++ STDMETHOD(SetInput)(THIS_ UINT index, IUnknown *input, UINT flags) PURE; ++}; ++ ++#ifdef __CRT_UUID_DECL ++__CRT_UUID_DECL(IDCompositionFilterEffect,0x30c421d5,0x8cb2,0x4e9f,0xb1,0x33,0x37,0xbe,0x27,0x0d,0x4a,0xc2); + #endif + ++ ++#undef INTERFACE ++#define INTERFACE IDCompositionSaturationEffect ++DECLARE_INTERFACE_IID_(IDCompositionSaturationEffect, IDCompositionFilterEffect, "A08DEBDA-3258-4FA4-9F16-9174D3FE93B1") ++{ ++#if defined(_MSC_VER) && defined(__cplusplus) ++ STDMETHOD(SetSaturation)(THIS_ float ratio) PURE; ++ STDMETHOD(SetSaturation)(THIS_ IDCompositionAnimation* animation) PURE; ++#else ++ STDMETHOD(SetSaturation)(THIS_ IDCompositionAnimation* animation) PURE; ++ STDMETHOD(SetSaturation)(THIS_ float ratio ) PURE; ++#endif ++}; ++ ++#ifdef __CRT_UUID_DECL ++__CRT_UUID_DECL(IDCompositionSaturationEffect,0xa08debda,0x3258,0x4fa4,0x9f,0x16,0x91,0x74,0xd3,0xfe,0x93,0xb1); ++#endif ++ ++ ++#undef INTERFACE ++#define INTERFACE IDCompositionGaussianBlurEffect ++DECLARE_INTERFACE_IID_(IDCompositionGaussianBlurEffect, IDCompositionFilterEffect, "45D4D0B7-1BD4-454E-8894-2BFA68443033") ++{ ++ ++#if defined(_MSC_VER) && defined(__cplusplus) ++ STDMETHOD(SetStandardDeviation)(THIS_ float amount) PURE; ++ STDMETHOD(SetStandardDeviation)(THIS_ IDCompositionAnimation* animation) PURE; ++#else ++ STDMETHOD(SetStandardDeviation)(THIS_ IDCompositionAnimation* animation) PURE; ++ STDMETHOD(SetStandardDeviation)(THIS_ float amount) PURE; ++#endif ++ STDMETHOD(SetBorderMode)(THIS_ D2D1_BORDER_MODE mode) PURE; ++}; ++ ++#ifdef __CRT_UUID_DECL ++__CRT_UUID_DECL(IDCompositionGaussianBlurEffect,0x45d4d0b7,0x1bd4,0x454e,0x88,0x94,0x2b,0xfa,0x68,0x44,0x30,0x33); ++#endif ++ ++ ++// WARNING: some of the arguments are replaced with void*, only what's used has been kept ++#undef INTERFACE ++#define INTERFACE IDCompositionDevice3 ++DECLARE_INTERFACE_IID_(IDCompositionDevice3, IDCompositionDevice2, "0987CB06-F916-48BF-8D35-CE7641781BD9") ++{ ++ STDMETHOD(CreateGaussianBlurEffect)(THIS_ IDCompositionGaussianBlurEffect **gaussianBlurEffect) PURE; ++ STDMETHOD(CreateBrightnessEffect)(THIS_ void **brightnessEffect) PURE; ++ STDMETHOD(CreateColorMatrixEffect)(THIS_ void **colorMatrixEffect) PURE; ++ STDMETHOD(CreateShadowEffect)(THIS_ void **shadowEffect) PURE; ++ STDMETHOD(CreateHueRotationEffect)(THIS_ void **hueRotationEffect) PURE; ++ STDMETHOD(CreateSaturationEffect)(THIS_ IDCompositionSaturationEffect **saturationEffect) PURE; ++ STDMETHOD(CreateTurbulenceEffect)(THIS_ void **turbulenceEffect) PURE; ++ STDMETHOD(CreateLinearTransferEffect)(THIS_ void **linearTransferEffect) PURE; ++ STDMETHOD(CreateTableTransferEffect)(THIS_ void **tableTransferEffect) PURE; ++ STDMETHOD(CreateCompositeEffect)(THIS_ void **compositeEffect) PURE; ++ STDMETHOD(CreateBlendEffect)(THIS_ void **blendEffect) PURE; ++ STDMETHOD(CreateArithmeticCompositeEffect)(THIS_ void **arithmeticCompositeEffect) PURE; ++ STDMETHOD(CreateAffineTransform2DEffect)(THIS_ void **affineTransform2dEffect) PURE; ++}; ++ ++#ifdef __CRT_UUID_DECL ++__CRT_UUID_DECL(IDCompositionDevice3,0x0987cb06,0xf916,0x48bf,0x8d,0x35,0xce,0x76,0x41,0x78,0x1b,0xd9); ++#endif ++ ++#endif // WINAPI_PARTITION_DESKTOP ++ + #if (_WIN32_WINNT >= 0x0A00) + + STDAPI DCompositionCreateDevice3(IUnknown *renderingDevice, REFIID iid, void **dcompositionDevice); +-- +2.27.0.windows.1 + ===================================== contrib/src/pthreads/rules.mak ===================================== @@ -13,8 +13,8 @@ ifdef HAVE_WINSTORE PKGS += winrt_headers PKGS_ALL += winrt_headers endif -PKGS += dxvahd -PKGS_ALL += dxvahd +PKGS += dxvahd dcomp +PKGS_ALL += dxvahd dcomp ifeq ($(HAVE_MINGW64_V8),true) PKGS_FOUND += winrt_headers dxvahd endif @@ -33,6 +33,7 @@ $(TARBALLS)/mingw-w64-v$(WINPTHREADS_VERSION).tar.bz2: pthreads: mingw-w64-v$(WINPTHREADS_VERSION).tar.bz2 .sum-pthreads #pthreads: mingw-w64-$(WINPTHREADS_HASH).tar.xz .sum-pthreads $(UNPACK) + $(APPLY) $(SRC)/pthreads/0001-dcomp.h-add-some-missing-interfaces.patch $(MOVE) .pthreads: pthreads @@ -55,3 +56,11 @@ pthreads: mingw-w64-v$(WINPTHREADS_VERSION).tar.bz2 .sum-pthreads mkdir -p -- "$(PREFIX)/include" cd $< && cp mingw-w64-headers/include/dxvahd.h "$(PREFIX)/include" touch $@ + +.sum-dcomp: .sum-pthreads + touch $@ + +.dcomp: pthreads + mkdir -p -- "$(PREFIX)/include" + cd $< && cp mingw-w64-headers/include/dcomp.h "$(PREFIX)/include" + touch $@ ===================================== modules/gui/qt/Makefile.am ===================================== @@ -278,6 +278,8 @@ libqt_plugin_la_SOURCES += \ gui/qt/maininterface/compositor_dcomp.cpp \ gui/qt/maininterface/compositor_dcomp.hpp \ gui/qt/maininterface/compositor_dcomp_error.hpp \ + gui/qt/maininterface/compositor_dcomp_acrylicsurface.hpp \ + gui/qt/maininterface/compositor_dcomp_acrylicsurface.cpp \ gui/qt/maininterface/compositor_dcomp_uisurface.cpp \ gui/qt/maininterface/compositor_dcomp_uisurface.hpp endif @@ -413,6 +415,7 @@ nodist_libqt_plugin_la_SOURCES += gui/qt/maininterface/main_interface_win32.moc. if HAVE_DCOMP nodist_libqt_plugin_la_SOURCES += \ + gui/qt/maininterface/compositor_dcomp_acrylicsurface.moc.cpp \ gui/qt/maininterface/compositor_dcomp.moc.cpp \ gui/qt/maininterface/compositor_dcomp_uisurface.moc.cpp endif @@ -770,6 +773,7 @@ libqt_plugin_la_QML = \ gui/qt/widgets/qml/CheckedDelegate.qml \ gui/qt/widgets/qml/ComboBoxExt.qml \ gui/qt/widgets/qml/ContextButton.qml \ + gui/qt/widgets/qml/AcrylicBackground.qml \ gui/qt/widgets/qml/AnimatedBackground.qml \ gui/qt/widgets/qml/CoverShadow.qml \ gui/qt/widgets/qml/CSDWindowButton.qml \ ===================================== modules/gui/qt/maininterface/compositor_dcomp.cpp ===================================== @@ -30,6 +30,7 @@ #include <QDesktopWidget> #include <QQuickWidget> #include <QLibrary> +#include <QScreen> #include <QOpenGLFunctions> #include <QOpenGLFramebufferObject> @@ -338,6 +339,16 @@ MainInterface* CompositorDirectComposition::makeMainInterface() m_uiSurface->setContent(m_ui->getComponent(), m_ui->createRootItem()); HR(m_rootVisual->AddVisual(m_uiVisual.Get(), FALSE, nullptr), "add ui visual to root"); HR(m_dcompDevice->Commit(), "commit UI visual"); + + auto resetAcrylicSurface = [this](QScreen * = nullptr) + { + m_acrylicSurface.reset(new CompositorDCompositionAcrylicSurface(m_intf, m_d3d11Device.Get())); + }; + + resetAcrylicSurface(); + connect(qGuiApp, &QGuiApplication::screenAdded, this, resetAcrylicSurface); + connect(qGuiApp, &QGuiApplication::screenRemoved, this, resetAcrylicSurface); + return m_mainInterface; } catch (const DXError& err) @@ -380,6 +391,7 @@ void CompositorDirectComposition::unloadGUI() m_rootVisual->RemoveVisual(m_uiVisual.Get()); m_uiVisual.Reset(); } + m_acrylicSurface.reset(); m_uiSurface.reset(); m_ui.reset(); m_taskbarWidget.reset(); @@ -436,4 +448,24 @@ Compositor::Type CompositorDirectComposition::type() const return Compositor::DirectCompositionCompositor; } +void CompositorDirectComposition::addVisual(Microsoft::WRL::ComPtr<IDCompositionVisual> visual) +{ + vlc_assert(m_rootVisual); + + HRESULT hr = m_rootVisual->AddVisual(visual.Get(), FALSE, m_videoVisual ? m_videoVisual.Get() : m_uiVisual.Get()); + if (FAILED(hr)) + msg_Err(m_intf, "failed to add visual, code: 0x%lX", hr); + + m_dcompDevice->Commit(); +} + +void CompositorDirectComposition::removeVisual(Microsoft::WRL::ComPtr<IDCompositionVisual> visual) +{ + auto hr = m_rootVisual->RemoveVisual(visual.Get()); + if (FAILED(hr)) + msg_Err(m_intf, "failed to remove visual, code: 0x%lX", hr); + + m_dcompDevice->Commit(); +} + } ===================================== modules/gui/qt/maininterface/compositor_dcomp.hpp ===================================== @@ -21,12 +21,18 @@ #include "compositor.hpp" #include <windows.h> + +# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x603) +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0603 +# endif #include <dcomp.h> #include <d3d11.h> #include <wrl.h> #include <dwmapi.h> #include "maininterface/mainui.hpp" +#include "compositor_dcomp_acrylicsurface.hpp" #include "compositor_dcomp_uisurface.hpp" #include "videosurface.hpp" #include "interface_window_handler.hpp" @@ -58,6 +64,9 @@ public: Type type() const override; + void addVisual(Microsoft::WRL::ComPtr<IDCompositionVisual> visual); + void removeVisual(Microsoft::WRL::ComPtr<IDCompositionVisual> visual); + private slots: void onSurfacePositionChanged(QPointF position); @@ -77,6 +86,7 @@ private: std::unique_ptr<WinTaskbarWidget> m_taskbarWidget; std::unique_ptr<CompositorDCompositionUISurface> m_uiSurface; + std::unique_ptr<CompositorDCompositionAcrylicSurface> m_acrylicSurface; vout_window_t *m_window = nullptr; std::unique_ptr<MainUI> m_ui; std::unique_ptr<VideoWindowHandler> m_videoWindowHandler; ===================================== modules/gui/qt/maininterface/compositor_dcomp_acrylicsurface.cpp ===================================== @@ -0,0 +1,445 @@ +/***************************************************************************** + * Copyright (C) 2021 the VideoLAN team + * + * Authors: Prince Gupta <[email protected]> + * + * 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_dcomp_acrylicsurface.hpp" + +#include <QWindow> +#include <QScreen> +#include <QLibrary> +#include <versionhelpers.h> + +#include "compositor_dcomp.hpp" + +namespace +{ + +template <typename F> +F loadFunction(QLibrary &library, const char *symbol) +{ + vlc_assert(library.isLoaded()); + + auto f = library.resolve(symbol); + if (!f) + { + const auto err = GetLastError(); + throw std::runtime_error(QString("failed to load %1, code %2").arg(QString(symbol), QString::number(err)).toStdString()); + } + + return reinterpret_cast<F>(f); +} + +bool isWinPreIron() +{ + typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + + auto ntdll = GetModuleHandleW(L"ntdll.dll"); + auto GetVersionInfo = reinterpret_cast<RtlGetVersionPtr>(GetProcAddress(ntdll, "RtlGetVersion")); + + if (GetVersionInfo) + { + RTL_OSVERSIONINFOW versionInfo = { }; + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + if (!GetVersionInfo(&versionInfo)) + return versionInfo.dwMajorVersion <= 10 + && versionInfo.dwBuildNumber < 20000; + } + + return false; +} + +} + +namespace vlc +{ + +CompositorDCompositionAcrylicSurface::CompositorDCompositionAcrylicSurface(qt_intf_t *intf_t, ID3D11Device *device, QObject *parent) + : QObject(parent) + , m_intf {intf_t} +{ + if (!init(device)) + { + m_intf = nullptr; + return; + } + + if (auto w = window()) + setActive(w->isActive()); + + qApp->installNativeEventFilter(this); +} + +CompositorDCompositionAcrylicSurface::~CompositorDCompositionAcrylicSurface() +{ + setActive(false); + + if (m_dummyWindow) + DestroyWindow(m_dummyWindow); +} + +bool CompositorDCompositionAcrylicSurface::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +{ + MSG* msg = static_cast<MSG*>( message ); + + if (!m_intf || msg->hwnd != hwnd()) + return false; + + switch (msg->message) + { + case WM_WINDOWPOSCHANGED: + { + sync(); + commitChanges(); + + requestReset(); // incase z-order changed + break; + } + case WM_ACTIVATE: + { + const int activeType = LOWORD(msg->wParam); + if ((activeType == WA_ACTIVE) || (activeType == WA_CLICKACTIVE)) + setActive(true); + else if (activeType == WA_INACTIVE) + setActive(false); + + break; + } + } + + return false; +} + + +bool CompositorDCompositionAcrylicSurface::init(ID3D11Device *device) +{ + if (!loadFunctions()) + return false; + + if (!createDevice(device)) + return false; + + if (!createDesktopVisual()) + return false; + + if (!createBackHostVisual()) + return false; + + m_leftMostScreenX = 0; + m_topMostScreenY = 0; + for (const auto screen : qGuiApp->screens()) + { + const auto geometry = screen->geometry(); + m_leftMostScreenX = std::min<int>(geometry.left(), m_leftMostScreenX); + m_topMostScreenY = std::min<int>(geometry.top(), m_topMostScreenY); + } + + return true; +} + +bool CompositorDCompositionAcrylicSurface::loadFunctions() +try +{ + QLibrary dwmapi("dwmapi.dll"); + if (!dwmapi.load()) + throw std::runtime_error("failed to dwmapi.dll, reason: " + dwmapi.errorString().toStdString()); + + lDwmpCreateSharedThumbnailVisual = loadFunction<DwmpCreateSharedThumbnailVisual>(dwmapi, MAKEINTRESOURCEA(147)); + lDwmpCreateSharedMultiWindowVisual = loadFunction<DwmpCreateSharedMultiWindowVisual>(dwmapi, MAKEINTRESOURCEA(163)); + + if (isWinPreIron()) + lDwmpUpdateSharedVirtualDesktopVisual = loadFunction<DwmpUpdateSharedVirtualDesktopVisual>(dwmapi, MAKEINTRESOURCEA(164)); //PRE-IRON + else + lDwmpUpdateSharedMultiWindowVisual = loadFunction<DwmpUpdateSharedMultiWindowVisual>(dwmapi, MAKEINTRESOURCEA(164)); //20xxx+ + + + QLibrary user32("user32.dll"); + if (!user32.load()) + throw std::runtime_error("failed to user32.dll, reason: " + user32.errorString().toStdString()); + + lSetWindowCompositionAttribute = loadFunction<SetWindowCompositionAttribute>(user32, "SetWindowCompositionAttribute"); + lGetWindowCompositionAttribute = loadFunction<GetWindowCompositionAttribute>(user32, "GetWindowCompositionAttribute"); + + return true; +} +catch (std::exception &err) +{ + msg_Err(m_intf, err.what()); + return false; +} + +bool CompositorDCompositionAcrylicSurface::createDevice(ID3D11Device *device) +try +{ + QLibrary dcompDll("DCOMP.dll"); + if (!dcompDll.load()) + throw DXError("failed to load DCOMP.dll", static_cast<HRESULT>(GetLastError())); + + DCompositionCreateDeviceFun myDCompositionCreateDevice3 = + reinterpret_cast<DCompositionCreateDeviceFun>(dcompDll.resolve("DCompositionCreateDevice3")); + if (!myDCompositionCreateDevice3) + throw DXError("failed to load DCompositionCreateDevice3 function", static_cast<HRESULT>(GetLastError())); + + using namespace Microsoft::WRL; + + ComPtr<IDXGIDevice> dxgiDevice; + HR(device->QueryInterface(dxgiDevice.GetAddressOf()), "query dxgi device"); + + ComPtr<IDCompositionDevice> dcompDevice1; + HR(myDCompositionCreateDevice3( + dxgiDevice.Get(), + __uuidof(IDCompositionDevice), + (void**)dcompDevice1.GetAddressOf()), "create composition device"); + + HR(dcompDevice1->QueryInterface(m_dcompDevice.GetAddressOf()), "dcompdevice not an IDCompositionDevice3"); + + HR(m_dcompDevice->CreateVisual(m_rootVisual.GetAddressOf()), "create root visual"); + + HR(m_dcompDevice->CreateRectangleClip(m_rootClip.GetAddressOf()), "create root clip"); + + HR(m_dcompDevice->CreateTranslateTransform(m_translateTransform.GetAddressOf()), "create translate transform"); + + HR(m_dcompDevice->CreateSaturationEffect(m_saturationEffect.GetAddressOf()), "create saturation effect"); + + HR(m_dcompDevice->CreateGaussianBlurEffect(m_gaussianBlur.GetAddressOf()), "create gaussian effect"); + + m_saturationEffect->SetSaturation(2); + + m_gaussianBlur->SetBorderMode(D2D1_BORDER_MODE_HARD); + m_gaussianBlur->SetStandardDeviation(20); + m_gaussianBlur->SetInput(0, m_saturationEffect.Get(), 0); + m_rootVisual->SetEffect(m_gaussianBlur.Get()); + + return true; +} +catch (const DXError &err) +{ + msg_Err(m_intf, "failed to initialise compositor acrylic surface: '%s' code: 0x%lX", err.what(), err.code()); + return false; +} + + +bool CompositorDCompositionAcrylicSurface::createDesktopVisual() +try +{ + vlc_assert(!m_desktopVisual); + auto desktopWindow = GetShellWindow(); + if (!desktopWindow) + throw DXError("failed to get desktop window", static_cast<HRESULT>(GetLastError())); + + const int desktopWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); + const int desktopHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + DWM_THUMBNAIL_PROPERTIES thumbnail; + thumbnail.dwFlags = DWM_TNP_SOURCECLIENTAREAONLY | DWM_TNP_VISIBLE | DWM_TNP_RECTDESTINATION | DWM_TNP_RECTSOURCE | DWM_TNP_OPACITY | DWM_TNP_ENABLE3D; + thumbnail.opacity = 255; + thumbnail.fVisible = TRUE; + thumbnail.fSourceClientAreaOnly = FALSE; + thumbnail.rcDestination = RECT{ 0, 0, desktopWidth, desktopHeight }; + thumbnail.rcSource = RECT{ 0, 0, desktopWidth, desktopHeight }; + + HTHUMBNAIL desktopThumbnail; + HR(lDwmpCreateSharedThumbnailVisual(hwnd(), desktopWindow, 2, &thumbnail, m_dcompDevice.Get(), (void**)m_desktopVisual.GetAddressOf(), &desktopThumbnail), "create desktop visual"); + HR(m_rootVisual->AddVisual(m_desktopVisual.Get(), FALSE, nullptr), "Add desktop visual"); + + return true; +} +catch (const DXError &err) +{ + msg_Err(m_intf, "failed to create desktop visual: '%s' code: 0x%lX", err.what(), err.code()); + return false; +} + +bool CompositorDCompositionAcrylicSurface::createBackHostVisual() +try +{ + vlc_assert(!m_dummyWindow); + // lDwmpCreateSharedMultiWindowVisual requires a window with disabled live (thumbnail) preview + // use a hidden dummy window to avoid disabling live preview of main window + m_dummyWindow = ::CreateWindowExA(WS_EX_TOOLWINDOW, "STATIC", "dummy", WS_VISIBLE, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + if (!m_dummyWindow) + throw DXError("failed to create dummy window", static_cast<HRESULT>(GetLastError())); + + int attr = DWM_CLOAKED_APP; + DwmSetWindowAttribute(m_dummyWindow, DWMWA_CLOAK, &attr, sizeof attr); + + BOOL enable = TRUE; + WINDOWCOMPOSITIONATTRIBDATA CompositionAttribute{}; + CompositionAttribute.Attrib = WCA_EXCLUDED_FROM_LIVEPREVIEW; + CompositionAttribute.pvData = &enable; + CompositionAttribute.cbData = sizeof(BOOL); + lSetWindowCompositionAttribute(m_dummyWindow, &CompositionAttribute); + + vlc_assert(!m_backHostVisual); + HR(lDwmpCreateSharedMultiWindowVisual(m_dummyWindow, m_dcompDevice.Get(), (void**)m_backHostVisual.GetAddressOf(), &m_backHostThumbnail) + , "failed to create shared multi visual"); + + updateVisual(); + + HR(m_rootVisual->AddVisual(m_backHostVisual.Get(), TRUE, m_desktopVisual.Get()), "Add backhost visual"); + + return true; +} +catch (const DXError &err) +{ + msg_Err(m_intf, "failed to create acrylic back host visual: '%s' code: 0x%lX", err.what(), err.code()); + return false; +} + +void CompositorDCompositionAcrylicSurface::sync() +{ + if (!m_intf || !hwnd()) + return; + + const int dx = std::abs(m_leftMostScreenX); + const int dy = std::abs(m_topMostScreenY); + + // window()->geometry()/frameGeometry() returns incorrect rect with CSD + RECT rect; + GetWindowRect(hwnd(), &rect); + m_rootClip->SetLeft((float)rect.left + dx); + m_rootClip->SetRight((float)rect.right + dx); + m_rootClip->SetTop((float)rect.top); + m_rootClip->SetBottom((float)rect.bottom); + m_rootVisual->SetClip(m_rootClip.Get()); + + int frameX = 0; + int frameY = 0; + + if (!m_intf->p_mi->useClientSideDecoration()) + { + frameX = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); + frameY = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION) + + GetSystemMetrics(SM_CXPADDEDBORDER); + } + else if (window()->visibility() & QWindow::Maximized) + { + // in maximized state CSDWin32EventHandler re-adds border + frameX = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); + frameY = GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER); + } + + m_translateTransform->SetOffsetX(-1 * (float)rect.left - frameX - dx); + m_translateTransform->SetOffsetY(-1 * (float)rect.top - frameY - dy); + m_rootVisual->SetTransform(m_translateTransform.Get()); +} + +void CompositorDCompositionAcrylicSurface::updateVisual() +{ + const auto w = window(); + if (!w || !w->screen()) + return; + + const auto screenRect = w->screen()->availableVirtualGeometry(); + RECT sourceRect {screenRect.left(), screenRect.top(), screenRect.right(), screenRect.bottom()}; + SIZE destinationSize {screenRect.width(), screenRect.height()}; + + HWND hwndExclusionList[2]; + hwndExclusionList[0] = hwnd(); + hwndExclusionList[1] = m_dummyWindow; + + HRESULT hr = S_FALSE; + + if (lDwmpUpdateSharedVirtualDesktopVisual) + hr = lDwmpUpdateSharedVirtualDesktopVisual(m_backHostThumbnail, NULL, 0, hwndExclusionList, 2, &sourceRect, &destinationSize); + else if (lDwmpUpdateSharedMultiWindowVisual) + hr = lDwmpUpdateSharedMultiWindowVisual(m_backHostThumbnail, NULL, 0, hwndExclusionList, 2, &sourceRect, &destinationSize, 1); + else + vlc_assert_unreachable(); + + if (FAILED(hr)) + qDebug("failed to update shared multi window visual"); +} + +void CompositorDCompositionAcrylicSurface::commitChanges() +{ + m_dcompDevice->Commit(); + DwmFlush(); +} + +void CompositorDCompositionAcrylicSurface::requestReset() +{ + if (m_resetPending) + return; + + m_resetPending = true; + m_resetTimer.start(5, Qt::PreciseTimer, this); +} + +void CompositorDCompositionAcrylicSurface::setActive(const bool newActive) +{ + if (newActive == m_active) + return; + + m_active = newActive; + if (m_active) + { + auto dcompositor = static_cast<vlc::CompositorDirectComposition *>(m_intf->p_compositor); + dcompositor->addVisual(m_rootVisual); + + updateVisual(); + sync(); + commitChanges(); + + // delay propagating changes to avoid flickering + QMetaObject::invokeMethod(this, [this]() + { + m_intf->p_mi->setHasAcrylicSurface(true); + }, Qt::QueuedConnection); + } + else + { + m_intf->p_mi->setHasAcrylicSurface(false); + + // delay propagating changes to avoid flickering + QMetaObject::invokeMethod(this, [this]() + { + auto dcompositor = static_cast<vlc::CompositorDirectComposition *>(m_intf->p_compositor); + dcompositor->removeVisual(m_rootVisual); + }, Qt::QueuedConnection); + } +} + +QWindow *CompositorDCompositionAcrylicSurface::window() +{ + return m_intf ? m_intf->p_compositor->interfaceMainWindow() : nullptr; +} + +HWND CompositorDCompositionAcrylicSurface::hwnd() +{ + auto w = window(); + return w->handle() ? (HWND)w->winId() : nullptr; +} + +void CompositorDCompositionAcrylicSurface::timerEvent(QTimerEvent *event) +{ + if (!event) + return; + + if (event->timerId() == m_resetTimer.timerId()) + { + m_resetPending = false; + m_resetTimer.stop(); + + updateVisual(); + sync(); + commitChanges(); + } +} + +} ===================================== modules/gui/qt/maininterface/compositor_dcomp_acrylicsurface.hpp ===================================== @@ -0,0 +1,233 @@ +/***************************************************************************** + * Copyright (C) 2021 the VideoLAN team + * + * Authors: Prince Gupta <[email protected]> + * + * 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_DCOMP_ACRYLICSURFACE_HPP +#define COMPOSITOR_DCOMP_ACRYLICSURFACE_HPP + +#include <QAbstractNativeEventFilter> +#include <QBasicTimer> + +#include <windows.h> + +# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x603) +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0603 +# endif + +#include <dcomp.h> +#include <d3d11.h> +#include <wrl.h> +#include <dwmapi.h> + +#include "compositor_dcomp_error.hpp" +#include "main_interface.hpp" + +// Windows Private APIs, taken from https://blog.adeltax.com/dwm-thumbnails-but-with-idcompositionvisual/ + +enum THUMBNAIL_TYPE { + TT_DEFAULT = 0x0, + TT_SNAPSHOT = 0x1, + TT_ICONIC = 0x2, + TT_BITMAPPENDING = 0x3, + TT_BITMAP = 0x4 +}; + +typedef HRESULT(WINAPI* DwmpCreateSharedThumbnailVisual)( + IN HWND hwndDestination, + IN HWND hwndSource, + IN DWORD dwThumbnailFlags, + IN DWM_THUMBNAIL_PROPERTIES* pThumbnailProperties, + IN VOID* pDCompDevice, + OUT VOID** ppVisual, + OUT PHTHUMBNAIL phThumbnailId); + +typedef HRESULT(WINAPI* DwmpQueryWindowThumbnailSourceSize)( + IN HWND hwndSource, + IN BOOL fSourceClientAreaOnly, + OUT SIZE* pSize); + +typedef HRESULT(WINAPI* DwmpQueryThumbnailType)( + IN HTHUMBNAIL hThumbnailId, + OUT THUMBNAIL_TYPE* thumbType); + +typedef HRESULT(WINAPI* DwmpCreateSharedMultiWindowVisual)( + IN HWND hwndDestination, + IN VOID* pDCompDevice, + OUT VOID** ppVisual, + OUT PHTHUMBNAIL phThumbnailId); + +//pre-cobalt/pre-iron +typedef HRESULT(WINAPI* DwmpUpdateSharedVirtualDesktopVisual)( + IN HTHUMBNAIL hThumbnailId, + IN HWND* phwndsInclude, + IN DWORD chwndsInclude, + IN HWND* phwndsExclude, + IN DWORD chwndsExclude, + OUT RECT* prcSource, + OUT SIZE* pDestinationSize); + + +//cobalt/iron (20xxx+) +//Change: function name + new DWORD parameter. +//Pass "1" in dwFlags. Feel free to explore other flags. +typedef HRESULT(WINAPI* DwmpUpdateSharedMultiWindowVisual)( + IN HTHUMBNAIL hThumbnailId, + IN HWND* phwndsInclude, + IN DWORD chwndsInclude, + IN HWND* phwndsExclude, + IN DWORD chwndsExclude, + OUT RECT* prcSource, + OUT SIZE* pDestinationSize, + IN DWORD dwFlags); + +#define DWM_TNP_FREEZE 0x100000 +#define DWM_TNP_ENABLE3D 0x4000000 +#define DWM_TNP_DISABLE3D 0x8000000 +#define DWM_TNP_FORCECVI 0x40000000 +#define DWM_TNP_DISABLEFORCECVI 0x80000000 + +enum WINDOWCOMPOSITIONATTRIB { + WCA_UNDEFINED = 0x0, + WCA_NCRENDERING_ENABLED = 0x1, + WCA_NCRENDERING_POLICY = 0x2, + WCA_TRANSITIONS_FORCEDISABLED = 0x3, + WCA_ALLOW_NCPAINT = 0x4, + WCA_CAPTION_BUTTON_BOUNDS = 0x5, + WCA_NONCLIENT_RTL_LAYOUT = 0x6, + WCA_FORCE_ICONIC_REPRESENTATION = 0x7, + WCA_EXTENDED_FRAME_BOUNDS = 0x8, + WCA_HAS_ICONIC_BITMAP = 0x9, + WCA_THEME_ATTRIBUTES = 0xA, + WCA_NCRENDERING_EXILED = 0xB, + WCA_NCADORNMENTINFO = 0xC, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 0xD, + WCA_VIDEO_OVERLAY_ACTIVE = 0xE, + WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 0xF, + WCA_DISALLOW_PEEK = 0x10, + WCA_CLOAK = 0x11, + WCA_CLOAKED = 0x12, + WCA_ACCENT_POLICY = 0x13, + WCA_FREEZE_REPRESENTATION = 0x14, + WCA_EVER_UNCLOAKED = 0x15, + WCA_VISUAL_OWNER = 0x16, + WCA_HOLOGRAPHIC = 0x17, + WCA_EXCLUDED_FROM_DDA = 0x18, + WCA_PASSIVEUPDATEMODE = 0x19, + WCA_LAST = 0x1A, +}; + +struct WINDOWCOMPOSITIONATTRIBDATA { + WINDOWCOMPOSITIONATTRIB Attrib; + void* pvData; + DWORD cbData; +}; + +typedef BOOL(WINAPI* SetWindowCompositionAttribute)( + IN HWND hwnd, + IN WINDOWCOMPOSITIONATTRIBDATA* pwcad); + +typedef BOOL(WINAPI* GetWindowCompositionAttribute)( + IN HWND hwnd, + OUT WINDOWCOMPOSITIONATTRIBDATA* pAttrData +); + +//Signature for DCompositionCreateDevice +typedef HRESULT (*DCompositionCreateDeviceFun)(IDXGIDevice *dxgiDevice, REFIID iid, void** dcompositionDevice); + +namespace vlc +{ + +/** + * @brief The CompositorDCompositionAcrylicSurface class + * Adds acrylic surface to the compositor_dcomp when the main window becomes active + * This acrylic surface is only valid for screen configuration at the time of initialization + */ + +class CompositorDCompositionAcrylicSurface + : public QObject + , public QAbstractNativeEventFilter +{ + Q_OBJECT + +public: + CompositorDCompositionAcrylicSurface(qt_intf_t *intf_t, ID3D11Device *device, QObject *parent = nullptr); + + ~CompositorDCompositionAcrylicSurface(); + +protected: + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; + + void timerEvent(QTimerEvent *event) override; + +private: + bool init(ID3D11Device *device); + bool loadFunctions(); + bool createDevice(ID3D11Device *device); + bool createDesktopVisual(); + bool createBackHostVisual(); + + void sync(); + void updateVisual(); + void commitChanges(); + void requestReset(); + + void setActive(bool newActive); + + QWindow *window(); + + HWND hwnd(); + + DwmpCreateSharedThumbnailVisual lDwmpCreateSharedThumbnailVisual {}; + + DwmpCreateSharedMultiWindowVisual lDwmpCreateSharedMultiWindowVisual {}; + + // use to update visual created with lDwmpCreateSharedMultiWindowVisual + //PRE-IRON + DwmpUpdateSharedVirtualDesktopVisual lDwmpUpdateSharedVirtualDesktopVisual {}; + + //20xxx+ + DwmpUpdateSharedMultiWindowVisual lDwmpUpdateSharedMultiWindowVisual {}; + + SetWindowCompositionAttribute lSetWindowCompositionAttribute {}; + GetWindowCompositionAttribute lGetWindowCompositionAttribute {}; + + HTHUMBNAIL m_backHostThumbnail = NULL; + HWND m_dummyWindow {}; + + Microsoft::WRL::ComPtr<IDCompositionDevice3> m_dcompDevice; + Microsoft::WRL::ComPtr<IDCompositionVisual2> m_rootVisual; + Microsoft::WRL::ComPtr<IDCompositionVisual2> m_backHostVisual; + Microsoft::WRL::ComPtr<IDCompositionVisual2> m_desktopVisual; + Microsoft::WRL::ComPtr<IDCompositionRectangleClip> m_rootClip; + Microsoft::WRL::ComPtr<IDCompositionTranslateTransform> m_translateTransform; + Microsoft::WRL::ComPtr<IDCompositionSaturationEffect> m_saturationEffect; + Microsoft::WRL::ComPtr<IDCompositionGaussianBlurEffect> m_gaussianBlur; + + qt_intf_t *m_intf {}; + QBasicTimer m_resetTimer; + bool m_resetPending = false; + bool m_active = false; + int m_leftMostScreenX = 0; + int m_topMostScreenY = 0; +}; + +} + +#endif ===================================== modules/gui/qt/maininterface/compositor_dcomp_uisurface.hpp ===================================== @@ -28,6 +28,12 @@ #include <vlc_interface.h> /* intf_thread_t */ #include <windows.h> + +# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x603) +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0603 +# endif + #include <d3d11.h> #include <dcomp.h> #include <wrl.h> ===================================== modules/gui/qt/maininterface/main_interface.cpp ===================================== @@ -342,6 +342,24 @@ void MainInterface::onWindowVisibilityChanged(QWindow::Visibility visibility) m_windowVisibility = visibility; } +void MainInterface::setUseAcrylicBackground(const bool v) +{ + if (m_useAcrylicBackground == v) + return; + + m_useAcrylicBackground = v; + emit useAcrylicBackgroundChanged(); +} + +void MainInterface::setHasAcrylicSurface(const bool v) +{ + if (m_hasAcrylicSurface == v) + return; + + m_hasAcrylicSurface = v; + emit hasAcrylicSurfaceChanged(); +} + void MainInterface::incrementIntfUserScaleFactor(bool increment) { if (increment) ===================================== modules/gui/qt/maininterface/main_interface.hpp ===================================== @@ -163,6 +163,8 @@ class MainInterface : public QObject Q_PROPERTY(bool canShowVideoPIP READ canShowVideoPIP CONSTANT FINAL) Q_PROPERTY(bool pinVideoControls READ pinVideoControls WRITE setPinVideoControls NOTIFY pinVideoControlsChanged FINAL) Q_PROPERTY(ControlbarProfileModel* controlbarProfileModel READ controlbarProfileModel CONSTANT FINAL) + Q_PROPERTY(bool useAcrylicBackground READ useAcrylicBackground NOTIFY useAcrylicBackgroundChanged FINAL) + Q_PROPERTY(bool hasAcrylicSurface READ hasAcrylicSurface NOTIFY hasAcrylicSurfaceChanged FINAL) public: /* tors */ @@ -217,6 +219,8 @@ public: inline ControlbarProfileModel* controlbarProfileModel() const { return m_controlbarProfileModel; } inline QUrl getDialogFilePath() const { return m_dialogFilepath; } inline void setDialogFilePath(const QUrl& filepath ){ m_dialogFilepath = filepath; } + inline bool useAcrylicBackground() const { return m_useAcrylicBackground; } + inline bool hasAcrylicSurface() const { return m_hasAcrylicSurface; } bool hasEmbededVideo() const; VideoSurfaceProvider* getVideoSurfaceProvider() const; @@ -290,6 +294,9 @@ protected: ControlbarProfileModel* m_controlbarProfileModel; + bool m_useAcrylicBackground = true; + bool m_hasAcrylicSurface = false; + public slots: void toggleUpdateSystrayMenu(); void showUpdateSystrayMenu(); @@ -306,6 +313,8 @@ public slots: void setPinVideoControls( bool ); void updateIntfScaleFactor(); void onWindowVisibilityChanged(QWindow::Visibility); + void setUseAcrylicBackground(bool); + void setHasAcrylicSurface(bool); void emitBoss(); void emitRaise(); @@ -356,6 +365,8 @@ signals: void intfScaleFactorChanged(); void pinVideoControlsChanged( bool ); + void useAcrylicBackgroundChanged(); + void hasAcrylicSurfaceChanged(); }; #endif ===================================== modules/gui/qt/maininterface/qml/BannerSources.qml ===================================== @@ -60,15 +60,18 @@ FocusScope { searchBox.expanded = true } - Rectangle { + Widgets.AcrylicBackground { + alternativeColor: VLCStyle.colors.topBanner + anchors.fill: parent + } + + Item { id: pLBannerSources property alias model: globalMenuGroup.model anchors.fill: parent - color: VLCStyle.colors.topBanner - Column { id: col anchors { @@ -161,6 +164,7 @@ FocusScope { delegate: Widgets.BannerTabButton { iconTxt: model.icon + color: "transparent" showText: globalToolbar.colapseTabButtons selected: model.index === selectedIndex onClicked: root.itemClicked(model.index) ===================================== modules/gui/qt/medialibrary/qml/MusicArtistsAlbums.qml ===================================== @@ -101,11 +101,10 @@ FocusScope { focus: visible anchors.fill: parent - Rectangle { + Widgets.AcrylicBackground { width: artistList.width height: artistList.height - color: VLCStyle.colors.bgAlt - opacity: .8 + alternativeColor: VLCStyle.colors.bgAlt } Row { ===================================== modules/gui/qt/player/qml/Player.qml ===================================== @@ -567,6 +567,8 @@ FocusScope { PL.PlaylistListView { id: playlistView + + useAcrylic: false focus: true anchors.fill: parent ===================================== modules/gui/qt/playlist/qml/PlaylistListView.qml ===================================== @@ -32,6 +32,8 @@ FocusScope { property alias model: listView.model + property alias useAcrylic: acrylicBackground.enabled + readonly property real minimumWidth: noContentInfoColumn.implicitWidth + leftPadding + rightPadding + @@ -102,10 +104,16 @@ FocusScope { } } - Rectangle { + Widgets.AcrylicBackground { + id: acrylicBackground + + anchors.fill: parent + alternativeColor: colors.bgAlt + } + + Item { id: parentRect anchors.fill: parent - color: colors.topBanner Widgets.DragItem { id: dragItem ===================================== modules/gui/qt/vlc.qrc ===================================== @@ -196,6 +196,7 @@ <file alias="ActionButtonPrimary.qml">widgets/qml/ActionButtonPrimary.qml</file> <file alias="BannerTabButton.qml">widgets/qml/BannerTabButton.qml</file> <file alias="BusyIndicatorExt.qml">widgets/qml/BusyIndicatorExt.qml</file> + <file alias="AcrylicBackground.qml">widgets/qml/AcrylicBackground.qml</file> <file alias="AnimatedBackground.qml">widgets/qml/AnimatedBackground.qml</file> <file alias="CSDWindowButton.qml">widgets/qml/CSDWindowButton.qml</file> <file alias="CSDWindowButtonSet.qml">widgets/qml/CSDWindowButtonSet.qml</file> ===================================== modules/gui/qt/widgets/qml/AcrylicBackground.qml ===================================== @@ -0,0 +1,45 @@ +/***************************************************************************** + * Copyright (C) 2021 VLC authors and VideoLAN + * + * Authors: Prince Gupta <[email protected]> + * + * 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. + *****************************************************************************/ + +import QtQuick 2.11 + +import "qrc:///style/" + +// This Component uses layering, avoid adding children to this widget +Item { + id: root + + readonly property bool usingAcrylic: visible && enabled && mainInterface.useAcrylicBackground && mainInterface.hasAcrylicSurface + + property color tintColor: VLCStyle.colors.setColorAlpha(VLCStyle.colors.bg, 0.7) + + property color alternativeColor: VLCStyle.colors.bgAlt + + layer.enabled: true + layer.effect: ShaderEffect { + property color overlay: root.usingAcrylic ? root.tintColor : root.alternativeColor + + blending: false + fragmentShader: " + uniform lowp vec4 overlay; + void main() { gl_FragColor = overlay; } + " + } +} View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/9ace5912de874bceb95a777f19cd36c2cfc3d437...b605fd25e97c75aa147b9bfd7fb530904eed27c7 -- View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/9ace5912de874bceb95a777f19cd36c2cfc3d437...b605fd25e97c75aa147b9bfd7fb530904eed27c7 You're receiving this email because of your account on code.videolan.org.
_______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
