Remove acrylic related things

They'll be moved to a separate repo instead

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2021-04-02 12:02:46 +08:00
parent 97d9009500
commit cdb7b87eb4
31 changed files with 106 additions and 2633 deletions

View File

@ -36,37 +36,21 @@ endif()
find_package(QT NAMES Qt6 Qt5 COMPONENTS Gui REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Gui REQUIRED)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Quick)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick)
set(SOURCES
qtacrylichelper.qrc
framelesshelper_global.h
framelesswindowsmanager.h
framelesswindowsmanager.cpp
utilities.h
utilities.cpp
qtacryliceffecthelper.h
qtacryliceffecthelper.cpp
)
if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
list(APPEND SOURCES
qtacrylicwidget.h
qtacrylicwidget.cpp
qtacrylicmainwindow.h
qtacrylicmainwindow.cpp
)
endif()
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
list(APPEND SOURCES
framelessquickhelper.h
framelessquickhelper.cpp
qtacrylicitem.h
qtacrylicitem.cpp
)
endif()
@ -75,8 +59,6 @@ if(WIN32)
utilities_win32.cpp
framelesshelper_win32.h
framelesshelper_win32.cpp
qtacryliceffecthelper_win32.h
qtacryliceffecthelper_win32.cpp
)
else()
list(APPEND SOURCES
@ -137,12 +119,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::GuiPrivate
)
if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets
)
endif()
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Quick

View File

@ -19,7 +19,6 @@ If you are using part of or all the code from this repository in your own projec
- Support tiled and stack windows by DWM (Win32 only).
- Won't cover the task bar when maximized (Win32 only).
- Won't block the auto-hide task bar when maximized (Win32 only).
- Support cross-platform blur effect inspired by [Microsoft's Acrylic blur](https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic).
## Usage

View File

@ -10,7 +10,6 @@ TODO
- Draggable.
- Resizable.
- Cross-platform: Windows, X11, Wayland, macOS (however, it doesn't look good on Windows, so you may want to try [`FramelessHelperWin`](/framelesshelper_win32.h) instead).
- Support blur effect inspired by [Microsoft's Acrylic blur](https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic).
As for the frame shadow and other window features, they mainly depend on your window manager.

View File

@ -14,7 +14,6 @@
- Support tiled and stack windows by DWM.
- Won't cover the task bar when maximized.
- Won't block the auto-hide task bar when maximized.
- Support blur effect inspired by [Microsoft's Acrylic blur](https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic).
## Usage

View File

@ -1,7 +1,7 @@
if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
#if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
add_subdirectory(widget)
add_subdirectory(mainwindow)
endif()
#endif()
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
add_subdirectory(quick)
endif()

View File

@ -23,12 +23,12 @@
*/
#include "../../framelesswindowsmanager.h"
#include "../../qtacrylicmainwindow.h"
#include "ui_MainWindow.h"
#include "ui_TitleBar.h"
#include <QtWidgets/qapplication.h>
#include <QtWidgets/qstyleoption.h>
#include <QtWidgets/qwidget.h>
#include <QtWidgets/qmainwindow.h>
#include <QtGui/qwindow.h>
int main(int argc, char *argv[])
@ -56,13 +56,12 @@ int main(int argc, char *argv[])
QApplication application(argc, argv);
QtAcrylicMainWindow *mainWindow = new QtAcrylicMainWindow;
mainWindow->setAcrylicEnabled(true);
const auto mainWindow = new QMainWindow;
Ui::MainWindow appMainWindow;
appMainWindow.setupUi(mainWindow);
QWidget *widget = new QWidget;
const auto widget = new QWidget;
Ui::TitleBar titleBarWidget;
titleBarWidget.setupUi(widget);
@ -82,11 +81,13 @@ int main(int argc, char *argv[])
mainWindow->showMaximized();
}
});
QObject::connect(mainWindow, &QtAcrylicMainWindow::windowStateChanged, [mainWindow, titleBarWidget](){
#if 0
QObject::connect(mainWindow, &QMainWindow::windowStateChanged, [mainWindow, titleBarWidget](){
titleBarWidget.maximizeButton->setChecked(mainWindow->isMaximized());
titleBarWidget.maximizeButton->setToolTip(mainWindow->isMaximized() ? QObject::tr("Restore") : QObject::tr("Maximize"));
});
QObject::connect(titleBarWidget.iconButton, &QPushButton::clicked, mainWindow, &QtAcrylicMainWindow::displaySystemMenu);
QObject::connect(titleBarWidget.iconButton, &QPushButton::clicked, mainWindow, &QMainWindow::displaySystemMenu);
#endif
QStyleOption option;
option.initFrom(mainWindow);
@ -105,7 +106,6 @@ int main(int argc, char *argv[])
FramelessWindowsManager::addIgnoreObject(win, appMainWindow.menubar);
mainWindow->resize(800, 600);
Q_EMIT mainWindow->windowStateChanged();
mainWindow->show();

View File

@ -23,7 +23,6 @@
*/
#include "../../framelessquickhelper.h"
#include "../../qtacrylicitem.h"
#include <QtGui/qguiapplication.h>
#include <QtQml/qqmlapplicationengine.h>
#include <QtQuickControls2/qquickstyle.h>
@ -65,7 +64,6 @@ int main(int argc, char *argv[])
#endif
qmlRegisterType<FramelessQuickHelper>("wangwenx190.Utils", 1, 0, "FramelessHelper");
qmlRegisterType<QtAcrylicItem>("wangwenx190.Utils", 1, 0, "AcrylicItem");
const QUrl mainQmlUrl(QStringLiteral("qrc:///qml/main.qml"));
const QMetaObject::Connection connection = QObject::connect(

View File

@ -33,7 +33,7 @@ Window {
width: 800
height: 600
title: qsTr("Hello, World!")
color: "transparent"
color: "#f0f0f0"
property int _flh_margin: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen)) ? 0 : (1 / Screen.devicePixelRatio)
@ -49,13 +49,6 @@ Window {
onTriggered: label.text = Qt.formatTime(new Date(), "hh:mm:ss")
}
AcrylicItem {
id: acrylicItem
anchors.fill: parent
acrylicEnabled: true
frameVisible: true
}
Rectangle {
id: titleBar
height: framelessHelper.titleBarHeight
@ -119,8 +112,15 @@ Window {
}
}
Component.onCompleted: {
framelessHelper.removeWindowFrame()
framelessHelper.setBlurEffectEnabled(true)
Rectangle {
id: windowFrame
anchors.fill: parent
color: "transparent"
border {
color: framelessHelper.nativeFrameColor
width: window._flh_margin
}
}
Component.onCompleted: framelessHelper.removeWindowFrame()
}

View File

@ -52,7 +52,6 @@ int main(int argc, char *argv[])
Widget widget;
widget.resize(800, 600);
widget.moveToDesktopCenter();
widget.show();
return QApplication::exec();

View File

@ -28,30 +28,22 @@
#include <QtCore/qdatetime.h>
#include <QtWidgets/qpushbutton.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qpainter.h>
#include "../../utilities.h"
#include "../../framelesswindowsmanager.h"
Widget::Widget(QWidget *parent) : QtAcrylicWidget(parent)
Widget::Widget(QWidget *parent) : QWidget(parent)
{
createWinId();
setAcrylicEnabled(true);
setupUi();
startTimer(500);
}
Widget::~Widget() = default;
void Widget::moveToDesktopCenter()
{
const QSize ss = Utilities::getScreenGeometry(nullptr).size();
const int newX = (ss.width() - width()) / 2;
const int newY = (ss.height() - height()) / 2;
move(newX, newY);
}
void Widget::showEvent(QShowEvent *event)
{
QtAcrylicWidget::showEvent(event);
QWidget::showEvent(event);
static bool inited = false;
if (!inited) {
FramelessWindowsManager::addWindow(windowHandle());
@ -61,13 +53,14 @@ void Widget::showEvent(QShowEvent *event)
void Widget::timerEvent(QTimerEvent *event)
{
QtAcrylicWidget::timerEvent(event);
QWidget::timerEvent(event);
m_label->setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss")));
}
void Widget::changeEvent(QEvent *event)
{
QtAcrylicWidget::changeEvent(event);
QWidget::changeEvent(event);
bool shouldUpdate = false;
if (event->type() == QEvent::WindowStateChange) {
if (isMaximized() || isFullScreen()) {
layout()->setContentsMargins(0, 0, 0, 0);
@ -76,6 +69,37 @@ void Widget::changeEvent(QEvent *event)
layout()->setContentsMargins(1, 1, 1, 1);
m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")});
}
shouldUpdate = true;
} else if (event->type() == QEvent::ActivationChange) {
shouldUpdate = true;
}
if (shouldUpdate) {
update();
}
}
void Widget::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
if (windowState() == Qt::WindowNoState) {
QPainter painter(this);
const int w = width();
const int h = height();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
using BorderLines = QList<QLine>;
#else
using BorderLines = QVector<QLine>;
#endif
const BorderLines lines = {
{0, 0, w, 0},
{w - 1, 0, w - 1, h},
{w, h - 1, 0, h - 1},
{0, h, 0, 0}
};
painter.save();
painter.setPen({Utilities::getNativeWindowFrameColor(), 1});
painter.drawLines(lines);
painter.restore();
}
}

View File

@ -24,14 +24,14 @@
#pragma once
#include "../../qtacrylicwidget.h"
#include <QtWidgets/qwidget.h>
QT_BEGIN_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QLabel)
QT_FORWARD_DECLARE_CLASS(QPushButton)
QT_END_NAMESPACE
class Widget : public QtAcrylicWidget
class Widget : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(Widget)
@ -40,12 +40,11 @@ public:
explicit Widget(QWidget *parent = nullptr);
~Widget() override;
Q_INVOKABLE void moveToDesktopCenter();
protected:
void showEvent(QShowEvent *event) override;
void timerEvent(QTimerEvent *event) override;
void changeEvent(QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
void setupUi();

View File

@ -65,13 +65,6 @@ namespace _flh_global {
[[maybe_unused]] const char _flh_borderHeight_flag[] = "_FRAMELESSHELPER_WINDOW_BORDER_HEIGHT";
[[maybe_unused]] const char _flh_titleBarHeight_flag[] = "_FRAMELESSHELPER_WINDOW_TITLE_BAR_HEIGHT";
[[maybe_unused]] const char _flh_ignoredObjects_flag[] = "_FRAMELESSHELPER_WINDOW_TITLE_BAR_IGNORED_OBJECTS";
[[maybe_unused]] const char _flh_acrylic_blurEnabled_flag[] = "_FRAMELESSHELPER_BLUR_ENABLED";
[[maybe_unused]] const char _flh_acrylic_blurMode_flag[] = "_FRAMELESSHELPER_BLUR_MODE";
[[maybe_unused]] const char _flh_acrylic_gradientColor_flag[] = "_FRAMELESSHELPER_BLUR_GRADIENT_COLOR";
[[maybe_unused]] const char _flh_acrylic_disableExtraProcess[] = "_FRAMELESSHELPER_DISABLE_EXTRA_PROCESS_FOR_BLUR";
[[maybe_unused]] const char _flh_acrylic_forceEnableOfficialMSWin10AcrylicBlur_flag[] = "_FRAMELESSHELPER_FORCE_ENABLE_MSWIN10_OFFICIAL_ACRYLIC_BLUR";
[[maybe_unused]] const char _flh_acrylic_forceEnableTraditionalBlur_flag[] = "_FRAMELESSHELPER_FORCE_ENABLE_TRADITIONAL_BLUR";
[[maybe_unused]] const char _flh_acrylic_forceDisableWallpaperBlur_flag[] = "_FRAMELESSHELPER_FORCE_DISABLE_WALLPAPER_BLUR";
[[maybe_unused]] const char _flh_useNativeTitleBar_flag[] = "_FRAMELESSHELPER_USE_NATIVE_TITLE_BAR";
[[maybe_unused]] const char _flh_preserveNativeFrame_flag[] = "_FRAMELESSHELPER_PRESERVE_NATIVE_WINDOW_FRAME";
[[maybe_unused]] const char _flh_forcePreserveNativeFrame_flag[] = "_FRAMELESSHELPER_FORCE_PRESERVE_NATIVE_WINDOW_FRAME";

View File

@ -412,6 +412,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
}
}
#if 0
// Fix the flickering issue while resizing.
// "clientRect->right += 1;" also works.
// The only draw back of this small trick is it will affect
@ -419,6 +420,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// larger than it should be. Be careful if you need to paint
// something manually either through QPainter or Qt Quick.
clientRect->bottom += 1;
#endif
// If the window bounds change, we're going to relayout and repaint
// anyway. Returning WVR_REDRAW avoids an extra paint before that of
// the old client pixels in the (now wrong) location, and thus makes
@ -661,38 +663,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
default:
break;
}
#if 0
// TODO: what if the user want to use the wallpaper blur all the time?
// Add an option to let the user choose what he wants.
if (Utilities::isWin10OrGreater()) {
if (window->property(_flh_global::_flh_acrylic_blurEnabled_flag).toBool()) {
bool shouldSwitchBlurMode = false;
if (msg->message == WM_ENTERSIZEMOVE) {
shouldSwitchBlurMode = true;
// Switch to the wallpaper blur temporarily due to the following issue:
// the window will become **VERY** laggy when it's being moved or resized.
// It's known as a bug of the API itself, currently no one knows how to fix it.
qunsetenv(_flh_global::_flh_acrylic_forceDisableWallpaperBlur_flag);
qunsetenv(_flh_global::_flh_acrylic_forceEnableTraditionalBlur_flag);
qunsetenv(_flh_global::_flh_acrylic_forceEnableOfficialMSWin10AcrylicBlur_flag);
}
if (msg->message == WM_EXITSIZEMOVE) {
shouldSwitchBlurMode = true;
// Switch back to the official Acrylic blur. That undocumented API won't cause any issues
// if we don't move or resize the window.
qputenv(_flh_global::_flh_acrylic_forceEnableTraditionalBlur_flag, "True");
qputenv(_flh_global::_flh_acrylic_forceDisableWallpaperBlur_flag, "True");
qputenv(_flh_global::_flh_acrylic_forceEnableOfficialMSWin10AcrylicBlur_flag, "True");
}
if (shouldSwitchBlurMode) {
const auto gradientColor = qvariant_cast<QColor>(window->property(_flh_global::_flh_acrylic_gradientColor_flag));
if (!Utilities::setBlurEffectEnabled(window, true, gradientColor)) {
qWarning() << "Failed to enable the blur effect.";
}
}
}
}
#endif
return false;
}

View File

@ -29,7 +29,14 @@
FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(parent)
{
startTimer(500);
connect(this, &FramelessQuickHelper::windowChanged, this, [this](QQuickWindow *win){
if (m_frameColorConnection) {
disconnect(m_frameColorConnection);
}
if (win) {
m_frameColorConnection = connect(win, &QQuickWindow::activeChanged, this, &FramelessQuickHelper::nativeFrameColorChanged);
}
});
}
int FramelessQuickHelper::borderWidth() const
@ -40,7 +47,7 @@ int FramelessQuickHelper::borderWidth() const
void FramelessQuickHelper::setBorderWidth(const int val)
{
FramelessWindowsManager::setBorderWidth(window(), val);
Q_EMIT borderWidthChanged(val);
Q_EMIT borderWidthChanged();
}
int FramelessQuickHelper::borderHeight() const
@ -51,7 +58,7 @@ int FramelessQuickHelper::borderHeight() const
void FramelessQuickHelper::setBorderHeight(const int val)
{
FramelessWindowsManager::setBorderHeight(window(), val);
Q_EMIT borderHeightChanged(val);
Q_EMIT borderHeightChanged();
}
int FramelessQuickHelper::titleBarHeight() const
@ -62,7 +69,7 @@ int FramelessQuickHelper::titleBarHeight() const
void FramelessQuickHelper::setTitleBarHeight(const int val)
{
FramelessWindowsManager::setTitleBarHeight(window(), val);
Q_EMIT titleBarHeightChanged(val);
Q_EMIT titleBarHeightChanged();
}
bool FramelessQuickHelper::resizable() const
@ -73,46 +80,18 @@ bool FramelessQuickHelper::resizable() const
void FramelessQuickHelper::setResizable(const bool val)
{
FramelessWindowsManager::setResizable(window(), val);
Q_EMIT resizableChanged(val);
Q_EMIT resizableChanged();
}
bool FramelessQuickHelper::lightThemeEnabled() const
QColor FramelessQuickHelper::nativeFrameColor() const
{
return Utilities::isLightThemeEnabled();
const auto win = window();
if (!win) {
return Qt::black;
}
return Utilities::getNativeWindowFrameColor(win->isActive());
}
bool FramelessQuickHelper::darkThemeEnabled() const
{
return Utilities::isDarkThemeEnabled();
}
#ifdef Q_OS_WINDOWS
bool FramelessQuickHelper::colorizationEnabled() const
{
return Utilities::isColorizationEnabled();
}
QColor FramelessQuickHelper::colorizationColor() const
{
return Utilities::getColorizationColor();
}
bool FramelessQuickHelper::highContrastModeEnabled() const
{
return Utilities::isHighContrastModeEnabled();
}
bool FramelessQuickHelper::darkFrameEnabled() const
{
return Utilities::isDarkFrameEnabled(window());
}
bool FramelessQuickHelper::transparencyEffectEnabled() const
{
return Utilities::isTransparencyEffectEnabled();
}
#endif
void FramelessQuickHelper::removeWindowFrame()
{
FramelessWindowsManager::addWindow(window());
@ -126,22 +105,3 @@ void FramelessQuickHelper::addIgnoreObject(QQuickItem *val)
}
FramelessWindowsManager::addIgnoreObject(window(), val);
}
void FramelessQuickHelper::timerEvent(QTimerEvent *event)
{
QQuickItem::timerEvent(event);
Q_EMIT lightThemeEnabledChanged(lightThemeEnabled());
Q_EMIT darkThemeEnabledChanged(darkThemeEnabled());
#ifdef Q_OS_WINDOWS
Q_EMIT colorizationEnabledChanged(colorizationEnabled());
Q_EMIT colorizationColorChanged(colorizationColor());
Q_EMIT highContrastModeEnabledChanged(highContrastModeEnabled());
Q_EMIT darkFrameEnabledChanged(darkFrameEnabled());
Q_EMIT transparencyEffectEnabledChanged(transparencyEffectEnabled());
#endif
}
void FramelessQuickHelper::setBlurEffectEnabled(const bool enabled, const QColor &gradientColor)
{
Utilities::setBlurEffectEnabled(window(), enabled, gradientColor);
}

View File

@ -32,21 +32,13 @@ class FRAMELESSHELPER_EXPORT FramelessQuickHelper : public QQuickItem
Q_OBJECT
Q_DISABLE_COPY_MOVE(FramelessQuickHelper)
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QML_ELEMENT
QML_NAMED_ELEMENT(FramelessHelper)
#endif
Q_PROPERTY(int borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged)
Q_PROPERTY(int borderHeight READ borderHeight WRITE setBorderHeight NOTIFY borderHeightChanged)
Q_PROPERTY(int titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged)
Q_PROPERTY(bool resizable READ resizable WRITE setResizable NOTIFY resizableChanged)
Q_PROPERTY(bool lightThemeEnabled READ lightThemeEnabled NOTIFY lightThemeEnabledChanged)
Q_PROPERTY(bool darkThemeEnabled READ darkThemeEnabled NOTIFY darkThemeEnabledChanged)
#ifdef Q_OS_WINDOWS
Q_PROPERTY(bool colorizationEnabled READ colorizationEnabled NOTIFY colorizationEnabledChanged)
Q_PROPERTY(QColor colorizationColor READ colorizationColor NOTIFY colorizationColorChanged)
Q_PROPERTY(bool highContrastModeEnabled READ highContrastModeEnabled NOTIFY highContrastModeEnabledChanged)
Q_PROPERTY(bool darkFrameEnabled READ darkFrameEnabled NOTIFY darkFrameEnabledChanged)
Q_PROPERTY(bool transparencyEffectEnabled READ transparencyEffectEnabled NOTIFY transparencyEffectEnabledChanged)
#endif
Q_PROPERTY(QColor nativeFrameColor READ nativeFrameColor NOTIFY nativeFrameColorChanged)
public:
explicit FramelessQuickHelper(QQuickItem *parent = nullptr);
@ -64,37 +56,19 @@ public:
bool resizable() const;
void setResizable(const bool val);
bool lightThemeEnabled() const;
bool darkThemeEnabled() const;
#ifdef Q_OS_WINDOWS
bool colorizationEnabled() const;
QColor colorizationColor() const;
bool highContrastModeEnabled() const;
bool darkFrameEnabled() const;
bool transparencyEffectEnabled() const;
#endif
QColor nativeFrameColor() const;
public Q_SLOTS:
void removeWindowFrame();
void addIgnoreObject(QQuickItem *val);
void setBlurEffectEnabled(const bool enabled = true, const QColor &gradientColor = {});
protected:
void timerEvent(QTimerEvent *event) override;
Q_SIGNALS:
void borderWidthChanged(int);
void borderHeightChanged(int);
void titleBarHeightChanged(int);
void resizableChanged(bool);
void lightThemeEnabledChanged(bool);
void darkThemeEnabledChanged(bool);
#ifdef Q_OS_WINDOWS
void colorizationEnabledChanged(bool);
void colorizationColorChanged(const QColor &);
void highContrastModeEnabledChanged(bool);
void darkFrameEnabledChanged(bool);
void transparencyEffectEnabledChanged(bool);
#endif
void borderWidthChanged();
void borderHeightChanged();
void titleBarHeightChanged();
void resizableChanged();
void nativeFrameColorChanged();
private:
QMetaObject::Connection m_frameColorConnection = {};
};

33
lib.pro
View File

@ -15,45 +15,26 @@ HEADERS += \
framelesshelper_global.h \
framelesshelper.h \
framelesswindowsmanager.h \
utilities.h \
qtacryliceffecthelper.h
utilities.h
SOURCES += \
framelesshelper.cpp \
framelesswindowsmanager.cpp \
utilities.cpp \
qtacryliceffecthelper.cpp
qtHaveModule(widgets) {
QT += widgets
HEADERS += \
qtacrylicwidget.h \
qtacrylicmainwindow.h
SOURCES += \
qtacrylicwidget.cpp \
qtacrylicmainwindow.cpp
}
utilities.cpp
qtHaveModule(quick) {
QT += quick
HEADERS += \
framelessquickhelper.h \
qtacrylicitem.h
SOURCES += \
framelessquickhelper.cpp \
qtacrylicitem.cpp
HEADERS += framelessquickhelper.h
SOURCES += framelessquickhelper.cpp
}
RESOURCES += qtacrylichelper.qrc
win32 {
DEFINES += \
WIN32_LEAN_AND_MEAN \
_CRT_SECURE_NO_WARNINGS \
UNICODE \
_UNICODE
HEADERS += \
framelesshelper_win32.h \
qtacryliceffecthelper_win32.h
HEADERS += framelesshelper_win32.h
SOURCES += \
utilities_win32.cpp \
framelesshelper_win32.cpp \
qtacryliceffecthelper_win32.cpp
LIBS += -luser32 -lshell32 -lgdi32 -ldwmapi -lole32
framelesshelper_win32.cpp
LIBS += -luser32 -lshell32 -lgdi32 -ldwmapi
RC_FILE = framelesshelper.rc
}

View File

@ -1,368 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "qtacryliceffecthelper.h"
#include "utilities.h"
#include <QtGui/qpainter.h>
#include <QtCore/qdebug.h>
#include <QtGui/qwindow.h>
#include <QtCore/qcoreapplication.h>
QtAcrylicEffectHelper::QtAcrylicEffectHelper(QObject *parent) : QObject(parent)
{
Q_INIT_RESOURCE(qtacrylichelper);
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
#ifdef Q_OS_MACOS
if (Utilities::shouldUseTraditionalBlur()) {
m_tintOpacity = 0.6;
}
#endif
#ifdef Q_OS_WINDOWS
m_frameColor = Utilities::getNativeWindowFrameColor(true);
#else
m_frameColor = Qt::black;
#endif
}
QtAcrylicEffectHelper::~QtAcrylicEffectHelper() = default;
void QtAcrylicEffectHelper::install(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return;
}
if (m_window != window) {
m_window = const_cast<QWindow *>(window);
connect(m_window, &QWindow::xChanged, this, &QtAcrylicEffectHelper::needsRepaint);
connect(m_window, &QWindow::yChanged, this, &QtAcrylicEffectHelper::needsRepaint);
connect(m_window, &QWindow::activeChanged, this, &QtAcrylicEffectHelper::needsRepaint);
// What's the difference between "visibility" and "window state"?
//connect(m_window, &QWindow::visibilityChanged, this, &QtAcrylicEffectHelper::needsRepaint);
connect(m_window, &QWindow::windowStateChanged, this, &QtAcrylicEffectHelper::needsRepaint);
#ifdef Q_OS_WINDOWS
//QtAcrylicWinEventFilter::setup();
#endif
}
}
void QtAcrylicEffectHelper::uninstall()
{
if (m_window) {
#ifdef Q_OS_WINDOWS
//QtAcrylicWinEventFilter::unsetup();
#endif
disconnect(m_window, &QWindow::xChanged, this, &QtAcrylicEffectHelper::needsRepaint);
disconnect(m_window, &QWindow::yChanged, this, &QtAcrylicEffectHelper::needsRepaint);
disconnect(m_window, &QWindow::activeChanged, this, &QtAcrylicEffectHelper::needsRepaint);
//disconnect(m_window, &QWindow::visibilityChanged, this, &QtAcrylicEffectHelper::needsRepaint);
disconnect(m_window, &QWindow::windowStateChanged, this, &QtAcrylicEffectHelper::needsRepaint);
m_window = nullptr;
}
}
void QtAcrylicEffectHelper::clearWallpaper()
{
if (!m_bluredWallpaper.isNull()) {
m_bluredWallpaper = {};
}
}
void QtAcrylicEffectHelper::showWarning() const
{
qDebug() << "The Acrylic blur effect has been enabled. Rendering acrylic material surfaces is highly GPU-intensive, which can slow down the application, increase the power consumption on the devices on which the application is running.";
}
QBrush QtAcrylicEffectHelper::getAcrylicBrush() const
{
return m_acrylicBrush;
}
QColor QtAcrylicEffectHelper::getTintColor() const
{
return m_tintColor;
}
qreal QtAcrylicEffectHelper::getTintOpacity() const
{
return m_tintOpacity;
}
qreal QtAcrylicEffectHelper::getNoiseOpacity() const
{
return m_noiseOpacity;
}
QPixmap QtAcrylicEffectHelper::getBluredWallpaper() const
{
return m_bluredWallpaper;
}
QColor QtAcrylicEffectHelper::getFrameColor() const
{
return m_frameColor;
}
qreal QtAcrylicEffectHelper::getFrameThickness() const
{
return m_frameThickness;
}
void QtAcrylicEffectHelper::setTintColor(const QColor &value)
{
if (!value.isValid()) {
qWarning() << value << "is not a valid color.";
return;
}
if (m_tintColor != value) {
m_tintColor = value;
}
}
void QtAcrylicEffectHelper::setTintOpacity(const qreal value)
{
if (m_tintOpacity != value) {
m_tintOpacity = value;
}
}
void QtAcrylicEffectHelper::setNoiseOpacity(const qreal value)
{
if (m_noiseOpacity != value) {
m_noiseOpacity = value;
}
}
void QtAcrylicEffectHelper::setFrameColor(const QColor &value)
{
if (!value.isValid()) {
qWarning() << value << "is not a valid color.";
return;
}
if (m_frameColor != value) {
m_frameColor = value;
}
}
void QtAcrylicEffectHelper::setFrameThickness(const qreal value)
{
if (m_frameThickness != value) {
m_frameThickness = value;
}
}
void QtAcrylicEffectHelper::paintWindowBackground(QPainter *painter, const QRegion &clip)
{
Q_ASSERT(painter);
Q_ASSERT(!clip.isEmpty());
if (!painter || clip.isEmpty()) {
return;
}
if (!checkWindow()) {
return;
}
painter->save();
painter->setClipRegion(clip);
paintBackground(painter, clip.boundingRect());
painter->restore();
}
void QtAcrylicEffectHelper::paintWindowBackground(QPainter *painter, const QRect &rect)
{
Q_ASSERT(painter);
Q_ASSERT(rect.isValid());
if (!painter || !rect.isValid()) {
return;
}
if (!checkWindow()) {
return;
}
painter->save();
painter->setClipRegion({rect});
paintBackground(painter, rect);
painter->restore();
}
void QtAcrylicEffectHelper::paintBackground(QPainter *painter, const QRect &rect)
{
Q_ASSERT(painter);
Q_ASSERT(rect.isValid());
if (!painter || !rect.isValid()) {
return;
}
if (!checkWindow()) {
return;
}
// TODO: should we limit it to Win32 only? Or should we do something about the
// acrylic brush instead?
if (Utilities::disableExtraProcessingForBlur()) {
return;
}
if (Utilities::shouldUseTraditionalBlur()) {
const QPainter::CompositionMode mode = painter->compositionMode();
painter->setCompositionMode(QPainter::CompositionMode_Clear);
painter->fillRect(rect, Qt::white);
painter->setCompositionMode(mode);
} else {
// Emulate blur behind window by blurring the desktop wallpaper.
updateBehindWindowBackground();
painter->drawPixmap(QPoint{0, 0}, m_bluredWallpaper, QRect{m_window->mapToGlobal(QPoint{0, 0}), rect.size()});
}
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
painter->setOpacity(1);
painter->fillRect(rect, m_acrylicBrush);
}
void QtAcrylicEffectHelper::paintWindowFrame(QPainter *painter, const QRect &rect)
{
Q_ASSERT(painter);
if (!painter) {
return;
}
if (!checkWindow()) {
return;
}
if (m_window->windowState() != Qt::WindowNoState) {
// We shouldn't draw the window frame when it's minimized/maximized/fullscreen.
return;
}
const int width = rect.isValid() ? rect.width() : m_window->width();
const int height = rect.isValid() ? rect.height() : m_window->height();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
using BorderLines = QList<QLineF>;
#else
using BorderLines = QVector<QLineF>;
#endif
#ifdef Q_OS_WINDOWS
const int internalFix = 1;
#else
const int internalFix = 0;
#endif
const BorderLines lines = {
{0, 0, static_cast<qreal>(width), 0},
{width - m_frameThickness, 0, width - m_frameThickness, static_cast<qreal>(height)},
{static_cast<qreal>(width), height - m_frameThickness - internalFix, 0, height - m_frameThickness - internalFix},
{0, static_cast<qreal>(height), 0, 0}
};
const bool active = m_window->isActive();
const QColor color = (active && m_frameColor.isValid() && (m_frameColor != Qt::transparent)) ? m_frameColor : Utilities::getNativeWindowFrameColor(active);
painter->save();
painter->setPen({color, 1});
painter->drawLines(lines);
painter->restore();
}
void QtAcrylicEffectHelper::updateAcrylicBrush(const QColor &alternativeTintColor)
{
const auto getAppropriateTintColor = [&alternativeTintColor, this]() -> QColor {
if (alternativeTintColor.isValid() && (alternativeTintColor != Qt::transparent)) {
return alternativeTintColor;
}
if (m_tintColor.isValid() && (m_tintColor != Qt::transparent)) {
return m_tintColor;
}
return Qt::white;
};
static const QImage noiseTexture(QStringLiteral(":/QtAcrylicHelper/Noise.png"));
QImage acrylicTexture({64, 64}, QImage::Format_ARGB32_Premultiplied);
QColor fillColor = Qt::transparent;
#ifdef Q_OS_WINDOWS
if (!Utilities::isOfficialMSWin10AcrylicBlurAvailable()) {
// Add a soft light layer for the background.
fillColor = Qt::white;
fillColor.setAlpha(150);
}
#endif
acrylicTexture.fill(fillColor);
QPainter painter(&acrylicTexture);
painter.setOpacity(m_tintOpacity);
painter.fillRect(QRect{0, 0, acrylicTexture.width(), acrylicTexture.height()}, getAppropriateTintColor());
painter.setOpacity(m_noiseOpacity);
painter.fillRect(QRect{0, 0, acrylicTexture.width(), acrylicTexture.height()}, noiseTexture);
m_acrylicBrush = acrylicTexture;
}
void QtAcrylicEffectHelper::updateBehindWindowBackground()
{
if (!checkWindow()) {
return;
}
if (!m_bluredWallpaper.isNull()) {
return;
}
const QSize size = Utilities::getScreenGeometry(m_window).size();
m_bluredWallpaper = QPixmap(size);
m_bluredWallpaper.fill(Qt::transparent);
QImage image = Utilities::getDesktopWallpaperImage();
// On some platforms we may not be able to get the desktop wallpaper, such as Linux and WebAssembly.
if (image.isNull()) {
return;
}
const Utilities::DesktopWallpaperAspectStyle aspectStyle = Utilities::getDesktopWallpaperAspectStyle();
QImage buffer(size, QImage::Format_ARGB32_Premultiplied);
#ifdef Q_OS_WINDOWS
if ((aspectStyle == Utilities::DesktopWallpaperAspectStyle::Central) ||
(aspectStyle == Utilities::DesktopWallpaperAspectStyle::KeepRatioFit)) {
buffer.fill(Utilities::getDesktopBackgroundColor());
}
#endif
if (aspectStyle == Utilities::DesktopWallpaperAspectStyle::IgnoreRatioFit ||
aspectStyle == Utilities::DesktopWallpaperAspectStyle::KeepRatioFit ||
aspectStyle == Utilities::DesktopWallpaperAspectStyle::KeepRatioByExpanding) {
Qt::AspectRatioMode mode;
if (aspectStyle == Utilities::DesktopWallpaperAspectStyle::IgnoreRatioFit) {
mode = Qt::IgnoreAspectRatio;
} else if (aspectStyle == Utilities::DesktopWallpaperAspectStyle::KeepRatioFit) {
mode = Qt::KeepAspectRatio;
} else {
mode = Qt::KeepAspectRatioByExpanding;
}
QSize newSize = image.size();
newSize.scale(size, mode);
image = image.scaled(newSize, Qt::IgnoreAspectRatio, Qt::FastTransformation);
}
if (aspectStyle == Utilities::DesktopWallpaperAspectStyle::Tiled) {
QPainter painterBuffer(&buffer);
painterBuffer.fillRect(QRect{{0, 0}, size}, image);
} else {
QPainter painterBuffer(&buffer);
const QRect rect = Utilities::alignedRect(Qt::LeftToRight, Qt::AlignCenter, image.size(), {{0, 0}, size});
painterBuffer.drawImage(rect.topLeft(), image);
}
QPainter painter(&m_bluredWallpaper);
#if 1
Utilities::blurImage(&painter, buffer, 128, false, false);
#else
painter.drawImage(QPoint{0, 0}, buffer);
#endif
}
bool QtAcrylicEffectHelper::checkWindow() const
{
if (m_window) {
return true;
}
qWarning() << "m_window is null, forgot to call \"QtAcrylicEffectHelper::install()\"?";
return false;
}

View File

@ -1,83 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "framelesshelper_global.h"
#include <QtGui/qbrush.h>
class FRAMELESSHELPER_EXPORT QtAcrylicEffectHelper : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(QtAcrylicEffectHelper)
public:
explicit QtAcrylicEffectHelper(QObject *parent = nullptr);
~QtAcrylicEffectHelper() override;
QBrush getAcrylicBrush() const;
QColor getTintColor() const;
qreal getTintOpacity() const;
qreal getNoiseOpacity() const;
QPixmap getBluredWallpaper() const;
QColor getFrameColor() const;
qreal getFrameThickness() const;
public Q_SLOTS:
void install(const QWindow *window);
void uninstall();
void clearWallpaper();
void showWarning() const;
void setTintColor(const QColor &value);
void setTintOpacity(const qreal value);
void setNoiseOpacity(const qreal value);
void setFrameColor(const QColor &value);
void setFrameThickness(const qreal value);
void paintWindowBackground(QPainter *painter, const QRegion &clip);
void paintWindowBackground(QPainter *painter, const QRect &rect);
void paintWindowFrame(QPainter *painter, const QRect &rect = {});
void updateAcrylicBrush(const QColor &alternativeTintColor = {});
private:
void paintBackground(QPainter *painter, const QRect &rect);
void updateBehindWindowBackground();
bool checkWindow() const;
Q_SIGNALS:
void needsRepaint();
private:
QWindow *m_window = nullptr;
QBrush m_acrylicBrush = {};
QColor m_tintColor = {};
qreal m_tintOpacity = 0.7;
qreal m_noiseOpacity = 0.04;
QPixmap m_bluredWallpaper = {};
QColor m_frameColor = {};
qreal m_frameThickness = 1.0;
};

View File

@ -1,129 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "qtacryliceffecthelper_win32.h"
#include "utilities.h"
#include <QtCore/qt_windows.h>
#include <QtCore/qcoreapplication.h>
#ifndef WM_DWMCOMPOSITIONCHANGED
// Only available since Windows Vista
#define WM_DWMCOMPOSITIONCHANGED 0x031E
#endif
#ifndef WM_DWMCOLORIZATIONCOLORCHANGED
// Only available since Windows Vista
#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
#endif
#ifndef WM_DPICHANGED
// Only available since Windows 8.1
#define WM_DPICHANGED 0x02E0
#endif
const int QtAcrylicWinUpdateEvent::QtAcrylicEffectChangeEventId = QEvent::registerEventType();
QtAcrylicWinUpdateEvent::QtAcrylicWinUpdateEvent(const bool clearWallpaper) : QEvent(static_cast<QEvent::Type>(QtAcrylicEffectChangeEventId))
{
m_shouldClearPreviousWallpaper = clearWallpaper;
}
QtAcrylicWinUpdateEvent::~QtAcrylicWinUpdateEvent() = default;
static QScopedPointer<QtAcrylicWinEventFilter> g_instance;
QtAcrylicWinEventFilter::QtAcrylicWinEventFilter() = default;
QtAcrylicWinEventFilter::~QtAcrylicWinEventFilter()
{
// FIXME
//unsetup();
}
void QtAcrylicWinEventFilter::setup()
{
if (g_instance.isNull()) {
g_instance.reset(new QtAcrylicWinEventFilter);
qApp->installNativeEventFilter(g_instance.data());
}
}
void QtAcrylicWinEventFilter::unsetup()
{
if (!g_instance.isNull()) {
qApp->removeNativeEventFilter(g_instance.data());
g_instance.reset();
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool QtAcrylicWinEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)
#else
bool QtAcrylicWinEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
#endif
{
Q_ASSERT(eventType == "windows_generic_MSG");
Q_ASSERT(message);
Q_UNUSED(result); // We don't need this parameter.
if ((eventType != "windows_generic_MSG") || !message) {
return false;
}
#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
const auto msg = *reinterpret_cast<MSG **>(message);
#else
const auto msg = static_cast<LPMSG>(message);
#endif
bool shouldUpdate = false;
bool shouldClearWallpaper = false;
switch (msg->message) {
case WM_SETTINGCHANGE: {
if (msg->wParam == SPI_SETDESKWALLPAPER) {
shouldClearWallpaper = true;
shouldUpdate = true;
}
if ((msg->wParam == 0) && (QString::fromWCharArray(reinterpret_cast<LPCWSTR>(msg->lParam)) == QStringLiteral("ImmersiveColorSet"))) {
shouldUpdate = true;
}
} break;
case WM_DPICHANGED: {
shouldClearWallpaper = true;
shouldUpdate = true;
} break;
case WM_THEMECHANGED:
case WM_DWMCOMPOSITIONCHANGED:
case WM_DWMCOLORIZATIONCOLORCHANGED:
shouldUpdate = true;
break;
default :
break;
}
if (shouldUpdate) {
const QWindow *window = Utilities::findWindow(reinterpret_cast<WId>(msg->hwnd));
if (window) {
QtAcrylicWinUpdateEvent event(shouldClearWallpaper);
QCoreApplication::sendEvent(const_cast<QWindow *>(window), &event);
}
}
return false;
}

View File

@ -1,62 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "framelesshelper_global.h"
#include <QtCore/qcoreevent.h>
#include <QtCore/qabstractnativeeventfilter.h>
class FRAMELESSHELPER_EXPORT QtAcrylicWinUpdateEvent : public QEvent
{
public:
static const int QtAcrylicEffectChangeEventId;
explicit QtAcrylicWinUpdateEvent(const bool clearWallpaper = false);
~QtAcrylicWinUpdateEvent() override;
inline bool shouldClearPreviousWallpaper() const
{
return m_shouldClearPreviousWallpaper;
}
private:
bool m_shouldClearPreviousWallpaper = false;
};
class FRAMELESSHELPER_EXPORT QtAcrylicWinEventFilter : public QAbstractNativeEventFilter
{
public:
explicit QtAcrylicWinEventFilter();
~QtAcrylicWinEventFilter() override;
static void setup();
static void unsetup();
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override;
#else
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override;
#endif
};

View File

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/QtAcrylicHelper">
<file alias="Noise.png">resources/noise.png</file>
</qresource>
</RCC>

View File

@ -1,177 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "qtacrylicitem.h"
#include <QtQuick/qquickwindow.h>
#include "utilities.h"
#include <QtCore/qdebug.h>
#include <QtGui/qpainter.h>
QtAcrylicItem::QtAcrylicItem(QQuickItem *parent) : QQuickPaintedItem(parent)
{
connect(this, &QtAcrylicItem::windowChanged, this, [this](QQuickWindow *win){
if (m_repaintConnection) {
disconnect(m_repaintConnection);
}
m_acrylicHelper.uninstall();
if (win) {
m_acrylicHelper.install(win);
m_acrylicHelper.updateAcrylicBrush();
m_repaintConnection = connect(&m_acrylicHelper, &QtAcrylicEffectHelper::needsRepaint, this, [this](){
update();
});
}
});
}
QtAcrylicItem::~QtAcrylicItem() = default;
void QtAcrylicItem::paint(QPainter *painter)
{
const QRect rect = {0, 0, qRound(width()), qRound(height())};
if (acrylicEnabled()) {
m_acrylicHelper.paintWindowBackground(painter, rect);
}
if (frameVisible()) {
m_acrylicHelper.paintWindowFrame(painter, rect);
}
}
QColor QtAcrylicItem::tintColor() const
{
const QColor color = m_acrylicHelper.getTintColor();
if (color.isValid() && (color != Qt::transparent)) {
return color;
} else {
return /*palette().color(backgroundRole())*/Qt::white;
}
}
void QtAcrylicItem::setTintColor(const QColor &value)
{
if (!value.isValid()) {
qWarning() << "Tint color not valid.";
return;
}
if (m_acrylicHelper.getTintColor() != value) {
m_acrylicHelper.setTintColor(value);
#if 0
QPalette pal = palette();
pal.setColor(backgroundRole(), m_acrylicHelper.getTintColor());
setPalette(pal);
#endif
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT tintColorChanged();
}
}
qreal QtAcrylicItem::tintOpacity() const
{
return m_acrylicHelper.getTintOpacity();
}
void QtAcrylicItem::setTintOpacity(const qreal value)
{
if (m_acrylicHelper.getTintOpacity() != value) {
m_acrylicHelper.setTintOpacity(value);
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT tintOpacityChanged();
}
}
qreal QtAcrylicItem::noiseOpacity() const
{
return m_acrylicHelper.getNoiseOpacity();
}
void QtAcrylicItem::setNoiseOpacity(const qreal value)
{
if (m_acrylicHelper.getNoiseOpacity() != value) {
m_acrylicHelper.setNoiseOpacity(value);
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT noiseOpacityChanged();
}
}
bool QtAcrylicItem::frameVisible() const
{
return m_frameVisible;
}
void QtAcrylicItem::setFrameVisible(const bool value)
{
if (m_frameVisible != value) {
m_frameVisible = value;
update();
Q_EMIT frameVisibleChanged();
}
}
QColor QtAcrylicItem::frameColor() const
{
return m_acrylicHelper.getFrameColor();
}
void QtAcrylicItem::setFrameColor(const QColor &value)
{
if (m_acrylicHelper.getFrameColor() != value) {
m_acrylicHelper.setFrameColor(value);
update();
Q_EMIT frameColorChanged();
}
}
qreal QtAcrylicItem::frameThickness() const
{
return m_acrylicHelper.getFrameThickness();
}
void QtAcrylicItem::setFrameThickness(const qreal value)
{
if (m_acrylicHelper.getFrameThickness() != value) {
m_acrylicHelper.setFrameThickness(value);
update();
Q_EMIT frameThicknessChanged();
}
}
bool QtAcrylicItem::acrylicEnabled() const
{
return m_acrylicEnabled;
}
void QtAcrylicItem::setAcrylicEnabled(const bool value)
{
if (m_acrylicEnabled != value) {
m_acrylicEnabled = value;
update();
Q_EMIT acrylicEnabledChanged();
if (m_acrylicEnabled) {
m_acrylicHelper.showWarning();
}
}
}

View File

@ -1,87 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "framelesshelper_global.h"
#include <QtQuick/qquickpainteditem.h>
#include "qtacryliceffecthelper.h"
class FRAMELESSHELPER_EXPORT QtAcrylicItem : public QQuickPaintedItem
{
Q_OBJECT
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QML_NAMED_ELEMENT(AcrylicItem)
#endif
Q_DISABLE_COPY_MOVE(QtAcrylicItem)
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged)
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged)
Q_PROPERTY(qreal noiseOpacity READ noiseOpacity WRITE setNoiseOpacity NOTIFY noiseOpacityChanged)
Q_PROPERTY(bool frameVisible READ frameVisible WRITE setFrameVisible NOTIFY frameVisibleChanged)
Q_PROPERTY(QColor frameColor READ frameColor WRITE setFrameColor NOTIFY frameColorChanged)
Q_PROPERTY(qreal frameThickness READ frameThickness WRITE setFrameThickness NOTIFY frameThicknessChanged)
Q_PROPERTY(bool acrylicEnabled READ acrylicEnabled WRITE setAcrylicEnabled NOTIFY acrylicEnabledChanged)
public:
explicit QtAcrylicItem(QQuickItem *parent = nullptr);
~QtAcrylicItem() override;
void paint(QPainter *painter) override;
QColor tintColor() const;
void setTintColor(const QColor &value);
qreal tintOpacity() const;
void setTintOpacity(const qreal value);
qreal noiseOpacity() const;
void setNoiseOpacity(const qreal value);
bool frameVisible() const;
void setFrameVisible(const bool value);
QColor frameColor() const;
void setFrameColor(const QColor &value);
qreal frameThickness() const;
void setFrameThickness(const qreal value);
bool acrylicEnabled() const;
void setAcrylicEnabled(const bool value);
Q_SIGNALS:
void tintColorChanged();
void tintOpacityChanged();
void noiseOpacityChanged();
void frameVisibleChanged();
void frameColorChanged();
void frameThicknessChanged();
void acrylicEnabledChanged();
private:
QtAcrylicEffectHelper m_acrylicHelper;
bool m_frameVisible = true;
QMetaObject::Connection m_repaintConnection = {};
bool m_acrylicEnabled = false;
};

View File

@ -1,207 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "qtacrylicmainwindow.h"
#include "utilities.h"
#include <QtCore/qdebug.h>
#include <QtGui/qevent.h>
#include <QtGui/qpainter.h>
QtAcrylicMainWindow::QtAcrylicMainWindow(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags)
{
}
QtAcrylicMainWindow::~QtAcrylicMainWindow() = default;
QColor QtAcrylicMainWindow::tintColor() const
{
const QColor color = m_acrylicHelper.getTintColor();
if (color.isValid() && (color != Qt::transparent)) {
return color;
} else {
return palette().color(backgroundRole());
}
}
void QtAcrylicMainWindow::setTintColor(const QColor &value)
{
if (!value.isValid()) {
qWarning() << "Tint color not valid.";
return;
}
if (m_acrylicHelper.getTintColor() != value) {
m_acrylicHelper.setTintColor(value);
QPalette pal = palette();
pal.setColor(backgroundRole(), m_acrylicHelper.getTintColor());
setPalette(pal);
//m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT tintColorChanged();
}
}
qreal QtAcrylicMainWindow::tintOpacity() const
{
return m_acrylicHelper.getTintOpacity();
}
void QtAcrylicMainWindow::setTintOpacity(const qreal value)
{
if (m_acrylicHelper.getTintOpacity() != value) {
m_acrylicHelper.setTintOpacity(value);
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT tintOpacityChanged();
}
}
qreal QtAcrylicMainWindow::noiseOpacity() const
{
return m_acrylicHelper.getNoiseOpacity();
}
void QtAcrylicMainWindow::setNoiseOpacity(const qreal value)
{
if (m_acrylicHelper.getNoiseOpacity() != value) {
m_acrylicHelper.setNoiseOpacity(value);
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT noiseOpacityChanged();
}
}
bool QtAcrylicMainWindow::frameVisible() const
{
return m_frameVisible;
}
void QtAcrylicMainWindow::setFrameVisible(const bool value)
{
if (m_frameVisible != value) {
m_frameVisible = value;
update();
Q_EMIT frameVisibleChanged();
}
}
QColor QtAcrylicMainWindow::frameColor() const
{
return m_acrylicHelper.getFrameColor();
}
void QtAcrylicMainWindow::setFrameColor(const QColor &value)
{
if (m_acrylicHelper.getFrameColor() != value) {
m_acrylicHelper.setFrameColor(value);
update();
Q_EMIT frameColorChanged();
}
}
qreal QtAcrylicMainWindow::frameThickness() const
{
return m_acrylicHelper.getFrameThickness();
}
void QtAcrylicMainWindow::setFrameThickness(const qreal value)
{
if (m_acrylicHelper.getFrameThickness() != value) {
m_acrylicHelper.setFrameThickness(value);
update();
Q_EMIT frameThicknessChanged();
}
}
bool QtAcrylicMainWindow::acrylicEnabled() const
{
return m_acrylicEnabled;
}
void QtAcrylicMainWindow::setAcrylicEnabled(const bool value)
{
if (m_acrylicEnabled != value) {
m_acrylicEnabled = value;
if (m_inited) {
Utilities::setBlurEffectEnabled(windowHandle(), m_acrylicEnabled);
}
setAutoFillBackground(!m_acrylicEnabled);
setAttribute(Qt::WA_NoSystemBackground, m_acrylicEnabled);
setAttribute(Qt::WA_OpaquePaintEvent, m_acrylicEnabled);
setBackgroundRole(m_acrylicEnabled ? QPalette::Base : QPalette::Window);
update();
Q_EMIT acrylicEnabledChanged();
if (m_acrylicEnabled) {
m_acrylicHelper.showWarning();
}
}
}
void QtAcrylicMainWindow::showEvent(QShowEvent *event)
{
QMainWindow::showEvent(event);
updateContentMargin();
if (!m_inited) {
m_acrylicHelper.install(windowHandle());
m_acrylicHelper.updateAcrylicBrush(tintColor());
connect(&m_acrylicHelper, &QtAcrylicEffectHelper::needsRepaint, this, qOverload<>(&QtAcrylicMainWindow::update));
Utilities::setBlurEffectEnabled(windowHandle(), m_acrylicEnabled);
m_inited = true;
}
}
void QtAcrylicMainWindow::updateContentMargin()
{
const qreal margin = (isMaximized() || isFullScreen()) ? 0.0 : (1.0 / devicePixelRatioF());
const int m = qRound(margin);
setContentsMargins(m, m, m, m);
}
void QtAcrylicMainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
const QRect rect = {0, 0, width(), height()};
if (acrylicEnabled()) {
m_acrylicHelper.paintWindowBackground(&painter, rect);
}
if (frameVisible()) {
m_acrylicHelper.paintWindowFrame(&painter, rect);
}
QMainWindow::paintEvent(event);
}
void QtAcrylicMainWindow::changeEvent(QEvent *event)
{
QMainWindow::changeEvent(event);
if (event->type() == QEvent::WindowStateChange) {
updateContentMargin();
Q_EMIT windowStateChanged();
}
}
void QtAcrylicMainWindow::displaySystemMenu()
{
#ifdef Q_OS_WINDOWS
Utilities::displaySystemMenu(windowHandle());
#endif
}

View File

@ -1,94 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "framelesshelper_global.h"
#include <QtWidgets/qmainwindow.h>
#include "qtacryliceffecthelper.h"
class FRAMELESSHELPER_EXPORT QtAcrylicMainWindow : public QMainWindow
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(QtAcrylicMainWindow)
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged)
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged)
Q_PROPERTY(qreal noiseOpacity READ noiseOpacity WRITE setNoiseOpacity NOTIFY noiseOpacityChanged)
Q_PROPERTY(bool frameVisible READ frameVisible WRITE setFrameVisible NOTIFY frameVisibleChanged)
Q_PROPERTY(QColor frameColor READ frameColor WRITE setFrameColor NOTIFY frameColorChanged)
Q_PROPERTY(qreal frameThickness READ frameThickness WRITE setFrameThickness NOTIFY frameThicknessChanged)
Q_PROPERTY(bool acrylicEnabled READ acrylicEnabled WRITE setAcrylicEnabled NOTIFY acrylicEnabledChanged)
public:
explicit QtAcrylicMainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = {});
~QtAcrylicMainWindow() override;
QColor tintColor() const;
void setTintColor(const QColor &value);
qreal tintOpacity() const;
void setTintOpacity(const qreal value);
qreal noiseOpacity() const;
void setNoiseOpacity(const qreal value);
bool frameVisible() const;
void setFrameVisible(const bool value);
QColor frameColor() const;
void setFrameColor(const QColor &value);
qreal frameThickness() const;
void setFrameThickness(const qreal value);
bool acrylicEnabled() const;
void setAcrylicEnabled(const bool value);
public Q_SLOTS:
void displaySystemMenu();
Q_SIGNALS:
void tintColorChanged();
void tintOpacityChanged();
void noiseOpacityChanged();
void frameVisibleChanged();
void frameColorChanged();
void frameThicknessChanged();
void acrylicEnabledChanged();
void windowStateChanged();
protected:
void showEvent(QShowEvent *event) override;
void paintEvent(QPaintEvent *event) override;
void changeEvent(QEvent *event) override;
private:
void updateContentMargin();
private:
QtAcrylicEffectHelper m_acrylicHelper;
bool m_frameVisible = true;
bool m_acrylicEnabled = false;
bool m_inited = false;
};

View File

@ -1,183 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "qtacrylicwidget.h"
#include "utilities.h"
#include <QtCore/qdebug.h>
#include <QtGui/qevent.h>
#include <QtGui/qpainter.h>
QtAcrylicWidget::QtAcrylicWidget(QWidget *parent) : QWidget(parent)
{
}
QtAcrylicWidget::~QtAcrylicWidget() = default;
QColor QtAcrylicWidget::tintColor() const
{
const QColor color = m_acrylicHelper.getTintColor();
if (color.isValid() && (color != Qt::transparent)) {
return color;
} else {
return palette().color(backgroundRole());
}
}
void QtAcrylicWidget::setTintColor(const QColor &value)
{
if (!value.isValid()) {
qWarning() << "Tint color not valid.";
return;
}
if (m_acrylicHelper.getTintColor() != value) {
m_acrylicHelper.setTintColor(value);
QPalette pal = palette();
pal.setColor(backgroundRole(), m_acrylicHelper.getTintColor());
setPalette(pal);
//m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT tintColorChanged();
}
}
qreal QtAcrylicWidget::tintOpacity() const
{
return m_acrylicHelper.getTintOpacity();
}
void QtAcrylicWidget::setTintOpacity(const qreal value)
{
if (m_acrylicHelper.getTintOpacity() != value) {
m_acrylicHelper.setTintOpacity(value);
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT tintOpacityChanged();
}
}
qreal QtAcrylicWidget::noiseOpacity() const
{
return m_acrylicHelper.getNoiseOpacity();
}
void QtAcrylicWidget::setNoiseOpacity(const qreal value)
{
if (m_acrylicHelper.getNoiseOpacity() != value) {
m_acrylicHelper.setNoiseOpacity(value);
m_acrylicHelper.updateAcrylicBrush(tintColor());
update();
Q_EMIT noiseOpacityChanged();
}
}
bool QtAcrylicWidget::frameVisible() const
{
return m_frameVisible;
}
void QtAcrylicWidget::setFrameVisible(const bool value)
{
if (m_frameVisible != value) {
m_frameVisible = value;
update();
Q_EMIT frameVisibleChanged();
}
}
QColor QtAcrylicWidget::frameColor() const
{
return m_acrylicHelper.getFrameColor();
}
void QtAcrylicWidget::setFrameColor(const QColor &value)
{
if (m_acrylicHelper.getFrameColor() != value) {
m_acrylicHelper.setFrameColor(value);
update();
Q_EMIT frameColorChanged();
}
}
qreal QtAcrylicWidget::frameThickness() const
{
return m_acrylicHelper.getFrameThickness();
}
void QtAcrylicWidget::setFrameThickness(const qreal value)
{
if (m_acrylicHelper.getFrameThickness() != value) {
m_acrylicHelper.setFrameThickness(value);
update();
Q_EMIT frameThicknessChanged();
}
}
bool QtAcrylicWidget::acrylicEnabled() const
{
return m_acrylicEnabled;
}
void QtAcrylicWidget::setAcrylicEnabled(const bool value)
{
if (m_acrylicEnabled != value) {
m_acrylicEnabled = value;
if (m_inited) {
Utilities::setBlurEffectEnabled(windowHandle(), m_acrylicEnabled);
}
setAutoFillBackground(!m_acrylicEnabled);
setAttribute(Qt::WA_NoSystemBackground, m_acrylicEnabled);
setAttribute(Qt::WA_OpaquePaintEvent, m_acrylicEnabled);
setBackgroundRole(m_acrylicEnabled ? QPalette::Base : QPalette::Window);
update();
Q_EMIT acrylicEnabledChanged();
if (m_acrylicEnabled) {
m_acrylicHelper.showWarning();
}
}
}
void QtAcrylicWidget::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
if (!m_inited) {
m_acrylicHelper.install(windowHandle());
m_acrylicHelper.updateAcrylicBrush(tintColor());
connect(&m_acrylicHelper, &QtAcrylicEffectHelper::needsRepaint, this, qOverload<>(&QtAcrylicWidget::update));
Utilities::setBlurEffectEnabled(windowHandle(), m_acrylicEnabled);
m_inited = true;
}
}
void QtAcrylicWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
const QRect rect = {0, 0, width(), height()};
if (acrylicEnabled()) {
m_acrylicHelper.paintWindowBackground(&painter, rect);
}
if (frameVisible()) {
m_acrylicHelper.paintWindowFrame(&painter, rect);
}
QWidget::paintEvent(event);
}

View File

@ -1,86 +0,0 @@
/*
* MIT License
*
* Copyright (C) 2021 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "framelesshelper_global.h"
#include <QtWidgets/qwidget.h>
#include "qtacryliceffecthelper.h"
class FRAMELESSHELPER_EXPORT QtAcrylicWidget : public QWidget
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(QtAcrylicWidget)
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged)
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged)
Q_PROPERTY(qreal noiseOpacity READ noiseOpacity WRITE setNoiseOpacity NOTIFY noiseOpacityChanged)
Q_PROPERTY(bool frameVisible READ frameVisible WRITE setFrameVisible NOTIFY frameVisibleChanged)
Q_PROPERTY(QColor frameColor READ frameColor WRITE setFrameColor NOTIFY frameColorChanged)
Q_PROPERTY(qreal frameThickness READ frameThickness WRITE setFrameThickness NOTIFY frameThicknessChanged)
Q_PROPERTY(bool acrylicEnabled READ acrylicEnabled WRITE setAcrylicEnabled NOTIFY acrylicEnabledChanged)
public:
explicit QtAcrylicWidget(QWidget *parent = nullptr);
~QtAcrylicWidget() override;
QColor tintColor() const;
void setTintColor(const QColor &value);
qreal tintOpacity() const;
void setTintOpacity(const qreal value);
qreal noiseOpacity() const;
void setNoiseOpacity(const qreal value);
bool frameVisible() const;
void setFrameVisible(const bool value);
QColor frameColor() const;
void setFrameColor(const QColor &value);
qreal frameThickness() const;
void setFrameThickness(const qreal value);
bool acrylicEnabled() const;
void setAcrylicEnabled(const bool value);
Q_SIGNALS:
void tintColorChanged();
void tintOpacityChanged();
void noiseOpacityChanged();
void frameVisibleChanged();
void frameColorChanged();
void frameThicknessChanged();
void acrylicEnabledChanged();
protected:
void showEvent(QShowEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private:
QtAcrylicEffectHelper m_acrylicHelper;
bool m_frameVisible = true;
bool m_acrylicEnabled = false;
bool m_inited = false;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

View File

@ -23,345 +23,8 @@
*/
#include "utilities.h"
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qscreen.h>
#include <QtGui/qpainter.h>
#include <QtGui/private/qmemrotate_p.h>
#include <QtCore/qdebug.h>
/*
* Copied from https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/effects/qpixmapfilter.cpp
* With minor modifications, most of them are format changes.
* They are exported functions of Qt, we can make use of them directly, but they are in the QtWidgets
* module, I don't want our library have such a dependency.
*/
#ifndef AVG
#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
#endif
#ifndef AVG16
#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
#endif
template<const int shift>
static inline int qt_static_shift(const int value)
{
if (shift == 0) {
return value;
} else if (shift > 0) {
return value << (uint(shift) & 0x1f);
} else {
return value >> (uint(-shift) & 0x1f);
}
}
template<const int aprec, const int zprec>
static inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, const int alpha)
{
QRgb *pixel = reinterpret_cast<QRgb *>(bptr);
#define Z_MASK (0xff << zprec)
const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
#undef Z_MASK
const int zR_zprec = zR >> aprec;
const int zG_zprec = zG >> aprec;
const int zB_zprec = zB >> aprec;
const int zA_zprec = zA >> aprec;
zR += alpha * (R_zprec - zR_zprec);
zG += alpha * (G_zprec - zG_zprec);
zB += alpha * (B_zprec - zB_zprec);
zA += alpha * (A_zprec - zA_zprec);
#define ZA_MASK (0xff << (zprec + aprec))
*pixel =
qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
| qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
| qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
| qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
#undef ZA_MASK
}
static const int alphaIndex = ((QSysInfo::ByteOrder == QSysInfo::BigEndian) ? 0 : 3);
template<const int aprec, const int zprec>
static inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, const int alpha)
{
const int A_zprec = int(*(bptr)) << zprec;
const int z_zprec = z >> aprec;
z += alpha * (A_zprec - z_zprec);
*(bptr) = z >> (zprec + aprec);
}
template<const int aprec, const int zprec, const bool alphaOnly>
static inline void qt_blurrow(QImage &im, const int line, const int alpha)
{
uchar *bptr = im.scanLine(line);
int zR = 0, zG = 0, zB = 0, zA = 0;
if (alphaOnly && (im.format() != QImage::Format_Indexed8)) {
bptr += alphaIndex;
}
const int stride = im.depth() >> 3;
const int im_width = im.width();
for (int index = 0; index < im_width; ++index) {
if (alphaOnly) {
qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
} else {
qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
}
bptr += stride;
}
bptr -= stride;
for (int index = im_width - 2; index >= 0; --index) {
bptr -= stride;
if (alphaOnly) {
qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
} else {
qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
}
}
}
/*
* expblur(QImage &img, const qreal radius)
*
* Based on exponential blur algorithm by Jani Huhtanen
*
* In-place blur of image 'img' with kernel
* of approximate radius 'radius'.
*
* Blurs with two sided exponential impulse
* response.
*
* aprec = precision of alpha parameter
* in fixed-point format 0.aprec
*
* zprec = precision of state parameters
* zR,zG,zB and zA in fp format 8.zprec
*/
template<const int aprec, const int zprec, const bool alphaOnly>
static inline void expblur(QImage &img, const qreal radius, const bool improvedQuality = false, const int transposed = 0)
{
qreal _radius = radius;
// halve the radius if we're using two passes
if (improvedQuality) {
_radius *= 0.5;
}
Q_ASSERT((img.format() == QImage::Format_ARGB32_Premultiplied)
|| (img.format() == QImage::Format_RGB32)
|| (img.format() == QImage::Format_Indexed8)
|| (img.format() == QImage::Format_Grayscale8));
// choose the alpha such that pixels at radius distance from a fully
// saturated pixel will have an alpha component of no greater than
// the cutOffIntensity
const qreal cutOffIntensity = 2;
const int alpha = _radius <= qreal(1e-5)
? ((1 << aprec)-1)
: qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / _radius)));
int img_height = img.height();
for (int row = 0; row < img_height; ++row) {
for (int i = 0; i <= int(improvedQuality); ++i) {
qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
}
}
// TODO: QImage(int width, int height, QImage::Format format)
// Why the argument order is inverted here? The application will crash if change it back.
QImage temp(img.height(), img.width(), img.format());
temp.setDevicePixelRatio(img.devicePixelRatio());
if (transposed >= 0) {
if (img.depth() == 8) {
qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
img.width(), img.height(), img.bytesPerLine(),
reinterpret_cast<quint8*>(temp.bits()),
temp.bytesPerLine());
} else {
qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
img.width(), img.height(), img.bytesPerLine(),
reinterpret_cast<quint32*>(temp.bits()),
temp.bytesPerLine());
}
} else {
if (img.depth() == 8) {
qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
img.width(), img.height(), img.bytesPerLine(),
reinterpret_cast<quint8*>(temp.bits()),
temp.bytesPerLine());
} else {
qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
img.width(), img.height(), img.bytesPerLine(),
reinterpret_cast<quint32*>(temp.bits()),
temp.bytesPerLine());
}
}
img_height = temp.height();
for (int row = 0; row < img_height; ++row) {
for (int i = 0; i <= int(improvedQuality); ++i) {
qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
}
}
if (transposed == 0) {
if (img.depth() == 8) {
qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
temp.width(), temp.height(), temp.bytesPerLine(),
reinterpret_cast<quint8*>(img.bits()),
img.bytesPerLine());
} else {
qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
temp.width(), temp.height(), temp.bytesPerLine(),
reinterpret_cast<quint32*>(img.bits()),
img.bytesPerLine());
}
} else {
img = temp;
}
}
static inline QImage qt_halfScaled(const QImage &source)
{
if (source.width() < 2 || source.height() < 2) {
return {};
}
QImage srcImage = source;
if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
// assumes grayscale
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
dest.setDevicePixelRatio(source.devicePixelRatio());
const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
qsizetype sx = srcImage.bytesPerLine();
qsizetype sx2 = sx << 1;
uchar *dst = reinterpret_cast<uchar*>(dest.bits());
qsizetype dx = dest.bytesPerLine();
int ww = dest.width();
int hh = dest.height();
for (int y = hh; y; --y, dst += dx, src += sx2) {
const uchar *p1 = src;
const uchar *p2 = src + sx;
uchar *q = dst;
for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2) {
*q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
}
}
return dest;
} else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
dest.setDevicePixelRatio(source.devicePixelRatio());
const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
qsizetype sx = srcImage.bytesPerLine();
qsizetype sx2 = sx << 1;
uchar *dst = reinterpret_cast<uchar*>(dest.bits());
qsizetype dx = dest.bytesPerLine();
int ww = dest.width();
int hh = dest.height();
for (int y = hh; y; --y, dst += dx, src += sx2) {
const uchar *p1 = src;
const uchar *p2 = src + sx;
uchar *q = dst;
for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
// alpha
q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
// rgb
const quint16 p16_1 = (p1[2] << 8) | p1[1];
const quint16 p16_2 = (p1[5] << 8) | p1[4];
const quint16 p16_3 = (p2[2] << 8) | p2[1];
const quint16 p16_4 = (p2[5] << 8) | p2[4];
const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
q[1] = result & 0xff;
q[2] = result >> 8;
}
}
return dest;
} else if ((source.format() != QImage::Format_ARGB32_Premultiplied) && (source.format() != QImage::Format_RGB32)) {
srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
dest.setDevicePixelRatio(source.devicePixelRatio());
const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
qsizetype sx = srcImage.bytesPerLine() >> 2;
qsizetype sx2 = sx << 1;
quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
qsizetype dx = dest.bytesPerLine() >> 2;
int ww = dest.width();
int hh = dest.height();
for (int y = hh; y; --y, dst += dx, src += sx2) {
const quint32 *p1 = src;
const quint32 *p2 = src + sx;
quint32 *q = dst;
for (int x = ww; x; --x, q++, p1 += 2, p2 += 2) {
*q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
}
}
return dest;
}
void Utilities::blurImage(QPainter *painter, QImage &blurImage, const qreal radius, const bool quality, const bool alphaOnly, const int transposed)
{
if ((blurImage.format() != QImage::Format_ARGB32_Premultiplied) && (blurImage.format() != QImage::Format_RGB32)) {
blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
qreal _radius = radius;
qreal scale = 1;
if ((_radius >= 4) && (blurImage.width() >= 2) && (blurImage.height() >= 2)) {
blurImage = qt_halfScaled(blurImage);
scale = 2;
_radius *= 0.5;
}
if (alphaOnly) {
expblur<12, 10, true>(blurImage, _radius, quality, transposed);
} else {
expblur<12, 10, false>(blurImage, _radius, quality, transposed);
}
if (painter) {
painter->scale(scale, scale);
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->drawImage(QRect{QPoint{0, 0}, blurImage.size() / blurImage.devicePixelRatio()}, blurImage);
}
}
void Utilities::blurImage(QImage &blurImage, const qreal radius, const bool quality, const int transposed)
{
if ((blurImage.format() == QImage::Format_Indexed8) || (blurImage.format() == QImage::Format_Grayscale8)) {
expblur<12, 10, true>(blurImage, radius, quality, transposed);
} else {
expblur<12, 10, false>(blurImage, radius, quality, transposed);
}
}
///////////////////////////////////////////////////
/*
* Copied from https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/styles/qstyle.cpp
* With minor modifications, most of them are format changes.
* They are exported functions of Qt, we can make use of them directly, but they are in the QtWidgets
* module, I don't want our library have such a dependency.
*/
static inline Qt::Alignment visualAlignment(const Qt::LayoutDirection direction, const Qt::Alignment alignment)
{
return QGuiApplicationPrivate::visualAlignment(direction, alignment);
}
QRect Utilities::alignedRect(const Qt::LayoutDirection direction, const Qt::Alignment alignment, const QSize &size, const QRect &rectangle)
{
const Qt::Alignment align = visualAlignment(direction, alignment);
int x = rectangle.x();
int y = rectangle.y();
const int w = size.width();
const int h = size.height();
if ((align & Qt::AlignVCenter) == Qt::AlignVCenter) {
y += rectangle.size().height() / 2 - h / 2;
} else if ((align & Qt::AlignBottom) == Qt::AlignBottom) {
y += rectangle.size().height() - h;
}
if ((align & Qt::AlignRight) == Qt::AlignRight) {
x += rectangle.size().width() - w;
} else if ((align & Qt::AlignHCenter) == Qt::AlignHCenter) {
x += rectangle.size().width() / 2 - w / 2;
}
return {x, y, w, h};
}
///////////////////////////////////////////////////
#include <QtGui/qguiapplication.h>
QWindow *Utilities::findWindow(const WId winId)
{
@ -380,37 +43,6 @@ QWindow *Utilities::findWindow(const WId winId)
return nullptr;
}
QRect Utilities::getScreenAvailableGeometry(const QWindow *window)
{
if (window) {
const QScreen *screen = window->screen();
if (screen) {
return screen->availableGeometry();
}
}
return QGuiApplication::primaryScreen()->availableGeometry();
}
bool Utilities::shouldUseWallpaperBlur()
{
return !shouldUseTraditionalBlur();
}
bool Utilities::disableExtraProcessingForBlur()
{
return qEnvironmentVariableIsSet(_flh_global::_flh_acrylic_disableExtraProcess);
}
bool Utilities::forceEnableTraditionalBlur()
{
return qEnvironmentVariableIsSet(_flh_global::_flh_acrylic_forceEnableTraditionalBlur_flag);
}
bool Utilities::forceDisableWallpaperBlur()
{
return qEnvironmentVariableIsSet(_flh_global::_flh_acrylic_forceDisableWallpaperBlur_flag);
}
bool Utilities::shouldUseNativeTitleBar()
{
return qEnvironmentVariableIsSet(_flh_global::_flh_useNativeTitleBar_flag);
@ -482,36 +114,3 @@ bool Utilities::isMouseInSpecificObjects(const QPointF &mousePos, const QObjectL
}
return false;
}
QRect Utilities::getScreenAvailableGeometry(const QPoint &pos)
{
if (!pos.isNull()) {
const QScreen *screen = QGuiApplication::screenAt(pos);
if (screen) {
return screen->availableGeometry();
}
}
return QGuiApplication::primaryScreen()->availableGeometry();
}
QRect Utilities::getScreenGeometry(const QWindow *window)
{
if (window) {
const QScreen *screen = window->screen();
if (screen) {
return screen->geometry();
}
}
return QGuiApplication::primaryScreen()->geometry();
}
QRect Utilities::getScreenGeometry(const QPoint &pos)
{
if (!pos.isNull()) {
const QScreen *screen = QGuiApplication::screenAt(pos);
if (screen) {
return screen->geometry();
}
}
return QGuiApplication::primaryScreen()->geometry();
}

View File

@ -37,21 +37,7 @@ enum class SystemMetric
TitleBarHeight
};
enum class DesktopWallpaperAspectStyle
{
Central,
Tiled,
IgnoreRatioFit, // Stretch
KeepRatioFit, // Fit
KeepRatioByExpanding, // Fill
Span
};
// Common
FRAMELESSHELPER_EXPORT bool shouldUseWallpaperBlur();
FRAMELESSHELPER_EXPORT bool shouldUseTraditionalBlur();
FRAMELESSHELPER_EXPORT bool setBlurEffectEnabled(const QWindow *window, const bool enabled, const QColor &gradientColor = {});
FRAMELESSHELPER_EXPORT int getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiAware, const bool forceSystemValue = false);
FRAMELESSHELPER_EXPORT bool isLightThemeEnabled();
@ -59,30 +45,14 @@ FRAMELESSHELPER_EXPORT bool isDarkThemeEnabled();
FRAMELESSHELPER_EXPORT QWindow *findWindow(const WId winId);
FRAMELESSHELPER_EXPORT QImage getDesktopWallpaperImage(const int screen = -1);
FRAMELESSHELPER_EXPORT QColor getDesktopBackgroundColor(const int screen = -1);
FRAMELESSHELPER_EXPORT DesktopWallpaperAspectStyle getDesktopWallpaperAspectStyle(const int screen = -1);
FRAMELESSHELPER_EXPORT QRect getScreenAvailableGeometry(const QWindow *window);
FRAMELESSHELPER_EXPORT QRect getScreenAvailableGeometry(const QPoint &pos);
FRAMELESSHELPER_EXPORT QRect getScreenGeometry(const QWindow *window);
FRAMELESSHELPER_EXPORT QRect getScreenGeometry(const QPoint &pos);
FRAMELESSHELPER_EXPORT QRect alignedRect(const Qt::LayoutDirection direction, const Qt::Alignment alignment, const QSize &size, const QRect &rectangle);
FRAMELESSHELPER_EXPORT void blurImage(QImage &blurImage, const qreal radius, const bool quality, const int transposed = 0);
FRAMELESSHELPER_EXPORT void blurImage(QPainter *painter, QImage &blurImage, const qreal radius, const bool quality, const bool alphaOnly, const int transposed = 0);
FRAMELESSHELPER_EXPORT bool disableExtraProcessingForBlur();
FRAMELESSHELPER_EXPORT bool forceEnableTraditionalBlur();
FRAMELESSHELPER_EXPORT bool forceDisableWallpaperBlur();
FRAMELESSHELPER_EXPORT bool shouldUseNativeTitleBar();
FRAMELESSHELPER_EXPORT bool isWindowFixedSize(const QWindow *window);
FRAMELESSHELPER_EXPORT bool isMouseInSpecificObjects(const QPointF &mousePos, const QObjectList &objects, const qreal dpr = 1.0);
FRAMELESSHELPER_EXPORT QColor getNativeWindowFrameColor(const bool isActive = true);
#ifdef Q_OS_WINDOWS
// Windows specific
FRAMELESSHELPER_EXPORT bool isWin7OrGreater();
@ -92,22 +62,16 @@ FRAMELESSHELPER_EXPORT bool isWin10OrGreater();
FRAMELESSHELPER_EXPORT bool isWin10OrGreater(const int subVer);
FRAMELESSHELPER_EXPORT bool isDwmBlurAvailable();
FRAMELESSHELPER_EXPORT bool isOfficialMSWin10AcrylicBlurAvailable();
FRAMELESSHELPER_EXPORT bool isColorizationEnabled();
FRAMELESSHELPER_EXPORT QColor getColorizationColor();
FRAMELESSHELPER_EXPORT bool isHighContrastModeEnabled();
FRAMELESSHELPER_EXPORT bool isDarkFrameEnabled(const QWindow *window);
FRAMELESSHELPER_EXPORT bool isTransparencyEffectEnabled();
FRAMELESSHELPER_EXPORT void triggerFrameChange(const QWindow *window);
FRAMELESSHELPER_EXPORT void updateFrameMargins(const QWindow *window, const bool reset);
FRAMELESSHELPER_EXPORT void updateQtFrameMargins(QWindow *window, const bool enable);
FRAMELESSHELPER_EXPORT quint32 getWindowDpi(const QWindow *window);
FRAMELESSHELPER_EXPORT QMargins getWindowNativeFrameMargins(const QWindow *window);
FRAMELESSHELPER_EXPORT QColor getNativeWindowFrameColor(const bool isActive = true);
FRAMELESSHELPER_EXPORT void displaySystemMenu(const QWindow *window, const QPoint &pos = {});
#endif

View File

@ -36,11 +36,7 @@
#include <QtCore/qt_windows.h>
#include <QtGui/qguiapplication.h>
#include <QtCore/qdebug.h>
#include <QtCore/qfileinfo.h>
#include <dwmapi.h>
#include <shobjidl_core.h>
#include <wininet.h>
#include <shlobj_core.h>
#include <QtGui/qpa/qplatformwindow.h>
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
#include <QtGui/qpa/qplatformnativeinterface.h>
@ -52,9 +48,6 @@
#else
#include <QtCore/qsysinfo.h>
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#include <QtCore/qscopeguard.h>
#endif
Q_DECLARE_METATYPE(QMargins)
@ -68,61 +61,8 @@ Q_DECLARE_METATYPE(QMargins)
#define SM_CXPADDEDBORDER 92
#endif
enum : WORD
{
DwmwaUseImmersiveDarkMode = 20,
DwmwaUseImmersiveDarkModeBefore20h1 = 19
};
using WINDOWCOMPOSITIONATTRIB = enum _WINDOWCOMPOSITIONATTRIB
{
WCA_ACCENT_POLICY = 19
};
using WINDOWCOMPOSITIONATTRIBDATA = struct _WINDOWCOMPOSITIONATTRIBDATA
{
WINDOWCOMPOSITIONATTRIB Attrib;
PVOID pvData;
SIZE_T cbData;
};
using ACCENT_STATE = enum _ACCENT_STATE
{
ACCENT_DISABLED = 0,
ACCENT_ENABLE_GRADIENT = 1,
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
ACCENT_ENABLE_BLURBEHIND = 3,
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803
ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809
ACCENT_INVALID_STATE = 6
};
using ACCENT_POLICY = struct _ACCENT_POLICY
{
ACCENT_STATE AccentState;
DWORD AccentFlags;
COLORREF GradientColor;
DWORD AnimationId;
};
using IMMERSIVE_HC_CACHE_MODE = enum _IMMERSIVE_HC_CACHE_MODE
{
IHCM_USE_CACHED_VALUE,
IHCM_REFRESH
};
using PREFERRED_APP_MODE = enum _PREFERRED_APP_MODE
{
Default,
AllowDark,
ForceDark,
ForceLight,
Max
};
static const QString g_dwmRegistryKey = QStringLiteral(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)");
static const QString g_personalizeRegistryKey = QStringLiteral(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)");
static const QString g_desktopRegistryKey = QStringLiteral(R"(HKEY_CURRENT_USER\Control Panel\Desktop)");
// The standard values of border width, border height and title bar height when DPI is 96.
static const int g_defaultBorderWidth = 8, g_defaultBorderHeight = 8, g_defaultTitleBarHeight = 31;
@ -139,16 +79,8 @@ using PROCESS_DPI_AWARENESS = enum _PROCESS_DPI_AWARENESS
PROCESS_PER_MONITOR_DPI_AWARE = 2
};
using SetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, WINDOWCOMPOSITIONATTRIBDATA *);
using ShouldAppsUseDarkModePtr = BOOL(WINAPI *)();
using AllowDarkModeForWindowPtr = BOOL(WINAPI *)(HWND, BOOL);
using AllowDarkModeForAppPtr = BOOL(WINAPI *)(BOOL);
using IsDarkModeAllowedForWindowPtr = BOOL(WINAPI *)(HWND);
using GetIsImmersiveColorUsingHighContrastPtr = BOOL(WINAPI *)(IMMERSIVE_HC_CACHE_MODE);
using RefreshImmersiveColorPolicyStatePtr = VOID(WINAPI *)();
using ShouldSystemUseDarkModePtr = BOOL(WINAPI *)();
using SetPreferredAppModePtr = PREFERRED_APP_MODE(WINAPI *)(PREFERRED_APP_MODE);
using IsDarkModeAllowedForAppPtr = BOOL(WINAPI *)();
using GetDpiForMonitorPtr = HRESULT(WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *);
using GetProcessDpiAwarenessPtr = HRESULT(WINAPI *)(HANDLE, PROCESS_DPI_AWARENESS *);
@ -160,18 +92,8 @@ using AdjustWindowRectExForDpiPtr = BOOL(WINAPI *)(LPRECT, DWORD, BOOL, DWORD, U
using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
{
_FLH_UTILITIES_WIN32_DATA() { load(); }
SetWindowCompositionAttributePtr SetWindowCompositionAttributePFN = nullptr;
ShouldAppsUseDarkModePtr ShouldAppsUseDarkModePFN = nullptr;
AllowDarkModeForWindowPtr AllowDarkModeForWindowPFN = nullptr;
AllowDarkModeForAppPtr AllowDarkModeForAppPFN = nullptr;
IsDarkModeAllowedForWindowPtr IsDarkModeAllowedForWindowPFN = nullptr;
GetIsImmersiveColorUsingHighContrastPtr GetIsImmersiveColorUsingHighContrastPFN = nullptr;
RefreshImmersiveColorPolicyStatePtr RefreshImmersiveColorPolicyStatePFN = nullptr;
ShouldSystemUseDarkModePtr ShouldSystemUseDarkModePFN = nullptr;
SetPreferredAppModePtr SetPreferredAppModePFN = nullptr;
IsDarkModeAllowedForAppPtr IsDarkModeAllowedForAppPFN = nullptr;
GetDpiForMonitorPtr GetDpiForMonitorPFN = nullptr;
GetProcessDpiAwarenessPtr GetProcessDpiAwarenessPFN = nullptr;
@ -181,10 +103,14 @@ using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
GetSystemMetricsForDpiPtr GetSystemMetricsForDpiPFN = nullptr;
AdjustWindowRectExForDpiPtr AdjustWindowRectExForDpiPFN = nullptr;
_FLH_UTILITIES_WIN32_DATA()
{
load();
}
void load()
{
QLibrary User32Dll(QStringLiteral("User32"));
SetWindowCompositionAttributePFN = reinterpret_cast<SetWindowCompositionAttributePtr>(User32Dll.resolve("SetWindowCompositionAttribute"));
GetDpiForWindowPFN = reinterpret_cast<GetDpiForWindowPtr>(User32Dll.resolve("GetDpiForWindow"));
GetDpiForSystemPFN = reinterpret_cast<GetDpiForSystemPtr>(User32Dll.resolve("GetDpiForSystem"));
GetSystemMetricsForDpiPFN = reinterpret_cast<GetSystemMetricsForDpiPtr>(User32Dll.resolve("GetSystemMetricsForDpi"));
@ -193,14 +119,7 @@ using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
QLibrary UxThemeDll(QStringLiteral("UxTheme"));
ShouldAppsUseDarkModePFN = reinterpret_cast<ShouldAppsUseDarkModePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(132)));
AllowDarkModeForWindowPFN = reinterpret_cast<AllowDarkModeForWindowPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(133)));
AllowDarkModeForAppPFN = reinterpret_cast<AllowDarkModeForAppPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(135)));
RefreshImmersiveColorPolicyStatePFN = reinterpret_cast<RefreshImmersiveColorPolicyStatePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(104)));
IsDarkModeAllowedForWindowPFN = reinterpret_cast<IsDarkModeAllowedForWindowPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(137)));
GetIsImmersiveColorUsingHighContrastPFN = reinterpret_cast<GetIsImmersiveColorUsingHighContrastPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(106)));
ShouldSystemUseDarkModePFN = reinterpret_cast<ShouldSystemUseDarkModePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(138)));
SetPreferredAppModePFN = reinterpret_cast<SetPreferredAppModePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(135)));
IsDarkModeAllowedForAppPFN = reinterpret_cast<IsDarkModeAllowedForAppPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(139)));
QLibrary SHCoreDll(QStringLiteral("SHCore"));
GetDpiForMonitorPFN = reinterpret_cast<GetDpiForMonitorPtr>(SHCoreDll.resolve("GetDpiForMonitor"));
@ -294,72 +213,6 @@ int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric,
return ret;
}
bool Utilities::setBlurEffectEnabled(const QWindow *window, const bool enabled, const QColor &gradientColor)
{
Q_ASSERT(window);
if (!window) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(window->winId());
Q_ASSERT(hwnd);
if (!hwnd) {
return false;
}
bool result = false;
// We prefer DwmEnableBlurBehindWindow on Windows 7.
if (isWin8OrGreater() && win32Data()->SetWindowCompositionAttributePFN) {
ACCENT_POLICY accentPolicy;
SecureZeroMemory(&accentPolicy, sizeof(accentPolicy));
WINDOWCOMPOSITIONATTRIBDATA wcaData;
SecureZeroMemory(&wcaData, sizeof(wcaData));
wcaData.Attrib = WCA_ACCENT_POLICY;
wcaData.pvData = &accentPolicy;
wcaData.cbData = sizeof(accentPolicy);
if (enabled) {
// The gradient color must be set otherwise it'll look like a classic blur.
// Use semi-transparent gradient color to get better appearance.
if (gradientColor.isValid()) {
accentPolicy.GradientColor = qRgba(gradientColor.blue(), gradientColor.green(), gradientColor.red(), gradientColor.alpha());
} else {
const QColor colorizationColor = getColorizationColor();
accentPolicy.GradientColor =
RGB(qRound(colorizationColor.red() * (colorizationColor.alpha() / 255.0) + 255 - colorizationColor.alpha()),
qRound(colorizationColor.green() * (colorizationColor.alpha() / 255.0) + 255 - colorizationColor.alpha()),
qRound(colorizationColor.blue() * (colorizationColor.alpha() / 255.0) + 255 - colorizationColor.alpha()));
}
if (isOfficialMSWin10AcrylicBlurAvailable()) {
accentPolicy.AccentState = ACCENT_ENABLE_ACRYLICBLURBEHIND;
if (!gradientColor.isValid()) {
accentPolicy.GradientColor = 0x01FFFFFF;
}
} else {
accentPolicy.AccentState = ACCENT_ENABLE_BLURBEHIND;
}
} else {
accentPolicy.AccentState = ACCENT_DISABLED;
}
result = (win32Data()->SetWindowCompositionAttributePFN(hwnd, &wcaData) != FALSE);
if (!result) {
qWarning() << "SetWindowCompositionAttribute failed.";
}
} else {
DWM_BLURBEHIND dwmBB;
SecureZeroMemory(&dwmBB, sizeof(dwmBB));
dwmBB.dwFlags = DWM_BB_ENABLE;
dwmBB.fEnable = enabled ? TRUE : FALSE;
result = SUCCEEDED(DwmEnableBlurBehindWindow(hwnd, &dwmBB));
if (!result) {
qWarning() << "DwmEnableBlurBehindWindow failed.";
}
}
if (result) {
const auto win = const_cast<QWindow *>(window);
win->setProperty(_flh_global::_flh_acrylic_blurEnabled_flag, enabled);
win->setProperty(_flh_global::_flh_acrylic_gradientColor_flag, gradientColor);
}
return result;
}
bool Utilities::isColorizationEnabled()
{
if (!isWin10OrGreater()) {
@ -411,50 +264,6 @@ bool Utilities::isDarkThemeEnabled()
return (ok && !lightThemeEnabled);
}
bool Utilities::isHighContrastModeEnabled()
{
HIGHCONTRASTW hc;
SecureZeroMemory(&hc, sizeof(hc));
hc.cbSize = sizeof(hc);
if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, 0, &hc, 0) == FALSE) {
qWarning() << "SystemParametersInfoW failed.";
return false;
}
return hc.dwFlags & HCF_HIGHCONTRASTON;
}
bool Utilities::isDarkFrameEnabled(const QWindow *window)
{
Q_ASSERT(window);
if (!window) {
return false;
}
if (!isWin10OrGreater(17763)) {
return false;
}
const auto hwnd = reinterpret_cast<HWND>(window->winId());
Q_ASSERT(hwnd);
if (!hwnd) {
return false;
}
BOOL result = FALSE;
const bool ok = SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkMode, &result, sizeof(result)))
|| SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkModeBefore20h1, &result, sizeof(result)));
return (ok && result);
}
bool Utilities::isTransparencyEffectEnabled()
{
if (!isWin10OrGreater()) {
return false;
}
// TODO: Is there an official Win32 API to do this?
bool ok = false;
const QSettings registry(g_personalizeRegistryKey, QSettings::NativeFormat);
const bool transparencyEnabled = registry.value(QStringLiteral("EnableTransparency"), 0).toULongLong(&ok) != 0;
return (ok && transparencyEnabled);
}
void Utilities::triggerFrameChange(const QWindow *window)
{
Q_ASSERT(window);
@ -488,243 +297,6 @@ void Utilities::updateFrameMargins(const QWindow *window, const bool reset)
}
}
QImage Utilities::getDesktopWallpaperImage(const int screen)
{
if (isWin8OrGreater()) {
if (SUCCEEDED(CoInitialize(nullptr))) {
IDesktopWallpaper* pDesktopWallpaper = nullptr;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
const auto cleanup = qScopeGuard([pDesktopWallpaper](){
if (pDesktopWallpaper) {
pDesktopWallpaper->Release();
}
CoUninitialize();
});
#endif
// TODO: Why CLSCTX_INPROC_SERVER failed?
if (SUCCEEDED(CoCreateInstance(CLSID_DesktopWallpaper, nullptr, CLSCTX_LOCAL_SERVER, IID_IDesktopWallpaper, reinterpret_cast<void **>(&pDesktopWallpaper))) && pDesktopWallpaper) {
UINT monitorCount = 0;
if (SUCCEEDED(pDesktopWallpaper->GetMonitorDevicePathCount(&monitorCount))) {
if (screen > int(monitorCount - 1)) {
qWarning() << "Screen number above total screen count.";
return {};
}
const UINT monitorIndex = qMax(screen, 0);
LPWSTR monitorId = nullptr;
if (SUCCEEDED(pDesktopWallpaper->GetMonitorDevicePathAt(monitorIndex, &monitorId)) && monitorId) {
LPWSTR wallpaperPath = nullptr;
if (SUCCEEDED(pDesktopWallpaper->GetWallpaper(monitorId, &wallpaperPath)) && wallpaperPath) {
CoTaskMemFree(monitorId);
const QString _path = QString::fromWCharArray(wallpaperPath);
CoTaskMemFree(wallpaperPath);
return QImage(_path);
} else {
CoTaskMemFree(monitorId);
qWarning() << "IDesktopWallpaper::GetWallpaper() failed.";
}
} else {
qWarning() << "IDesktopWallpaper::GetMonitorDevicePathAt() failed";
}
} else {
qWarning() << "IDesktopWallpaper::GetMonitorDevicePathCount() failed";
}
} else {
qWarning() << "Failed to create COM instance - DesktopWallpaper.";
}
} else {
qWarning() << "Failed to initialize COM.";
}
qDebug() << "The IDesktopWallpaper interface failed. Trying the IActiveDesktop interface instead.";
}
if (SUCCEEDED(CoInitialize(nullptr))) {
IActiveDesktop *pActiveDesktop = nullptr;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
const auto cleanup = qScopeGuard([pActiveDesktop](){
if (pActiveDesktop) {
pActiveDesktop->Release();
}
CoUninitialize();
});
#endif
if (SUCCEEDED(CoCreateInstance(CLSID_ActiveDesktop, nullptr, CLSCTX_INPROC_SERVER, IID_IActiveDesktop, reinterpret_cast<void **>(&pActiveDesktop))) && pActiveDesktop) {
const auto wallpaperPath = new WCHAR[MAX_PATH];
// TODO: AD_GETWP_BMP, AD_GETWP_IMAGE, AD_GETWP_LAST_APPLIED. What's the difference?
if (SUCCEEDED(pActiveDesktop->GetWallpaper(wallpaperPath, MAX_PATH, AD_GETWP_LAST_APPLIED))) {
const QString _path = QString::fromWCharArray(wallpaperPath);
delete [] wallpaperPath;
return QImage(_path);
} else {
qWarning() << "IActiveDesktop::GetWallpaper() failed.";
}
} else {
qWarning() << "Failed to create COM instance - ActiveDesktop.";
}
} else {
qWarning() << "Failed to initialize COM.";
}
qDebug() << "Shell API failed. Using SystemParametersInfoW instead.";
const auto wallpaperPath = new WCHAR[MAX_PATH];
if (SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaperPath, 0) != FALSE) {
const QString _path = QString::fromWCharArray(wallpaperPath);
delete [] wallpaperPath;
return QImage(_path);
}
qWarning() << "SystemParametersInfoW failed. Reading from the registry instead.";
const QSettings settings(g_desktopRegistryKey, QSettings::NativeFormat);
const QString path = settings.value(QStringLiteral("WallPaper")).toString();
if (QFileInfo::exists(path)) {
return QImage(path);
}
qWarning() << "Failed to read the registry.";
return {};
}
QColor Utilities::getDesktopBackgroundColor(const int screen)
{
Q_UNUSED(screen);
if (isWin8OrGreater()) {
if (SUCCEEDED(CoInitialize(nullptr))) {
IDesktopWallpaper *pDesktopWallpaper = nullptr;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
const auto cleanup = qScopeGuard([pDesktopWallpaper]() {
if (pDesktopWallpaper) {
pDesktopWallpaper->Release();
}
CoUninitialize();
});
#endif
// TODO: Why CLSCTX_INPROC_SERVER failed?
if (SUCCEEDED(CoCreateInstance(CLSID_DesktopWallpaper, nullptr, CLSCTX_LOCAL_SERVER, IID_IDesktopWallpaper, reinterpret_cast<void **>(&pDesktopWallpaper))) && pDesktopWallpaper) {
COLORREF color = 0;
if (SUCCEEDED(pDesktopWallpaper->GetBackgroundColor(&color))) {
return QColor::fromRgba(color);
} else {
qWarning() << "IDesktopWallpaper::GetBackgroundColor() failed.";
}
} else {
qWarning() << "Failed to create COM instance - DesktopWallpaper.";
}
} else {
qWarning() << "Failed to initialize COM.";
}
qDebug() << "The IDesktopWallpaper interface failed.";
}
// TODO: Is there any other way to get the background color? Traditional Win32 API? Registry?
// Is there a Shell API for Win7?
return Qt::black;
}
Utilities::DesktopWallpaperAspectStyle Utilities::getDesktopWallpaperAspectStyle(const int screen)
{
Q_UNUSED(screen);
if (isWin8OrGreater()) {
if (SUCCEEDED(CoInitialize(nullptr))) {
IDesktopWallpaper *pDesktopWallpaper = nullptr;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
const auto cleanup = qScopeGuard([pDesktopWallpaper](){
if (pDesktopWallpaper) {
pDesktopWallpaper->Release();
}
CoUninitialize();
});
#endif
// TODO: Why CLSCTX_INPROC_SERVER failed?
if (SUCCEEDED(CoCreateInstance(CLSID_DesktopWallpaper, nullptr, CLSCTX_LOCAL_SERVER, IID_IDesktopWallpaper, reinterpret_cast<void **>(&pDesktopWallpaper))) && pDesktopWallpaper) {
DESKTOP_WALLPAPER_POSITION position = DWPOS_FILL;
if (SUCCEEDED(pDesktopWallpaper->GetPosition(&position))) {
switch (position) {
case DWPOS_CENTER:
return DesktopWallpaperAspectStyle::Central;
case DWPOS_TILE:
return DesktopWallpaperAspectStyle::Tiled;
case DWPOS_STRETCH:
return DesktopWallpaperAspectStyle::IgnoreRatioFit;
case DWPOS_FIT:
return DesktopWallpaperAspectStyle::KeepRatioFit;
case DWPOS_FILL:
return DesktopWallpaperAspectStyle::KeepRatioByExpanding;
case DWPOS_SPAN:
return DesktopWallpaperAspectStyle::Span;
}
} else {
qWarning() << "IDesktopWallpaper::GetPosition() failed.";
}
} else {
qWarning() << "Failed to create COM instance - DesktopWallpaper.";
}
} else {
qWarning() << "Failed to initialize COM.";
}
qDebug() << "The IDesktopWallpaper interface failed. Trying the IActiveDesktop interface instead.";
}
if (SUCCEEDED(CoInitialize(nullptr))) {
IActiveDesktop *pActiveDesktop = nullptr;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
const auto cleanup = qScopeGuard([pActiveDesktop](){
if (pActiveDesktop) {
pActiveDesktop->Release();
}
CoUninitialize();
});
#endif
if (SUCCEEDED(CoCreateInstance(CLSID_ActiveDesktop, nullptr, CLSCTX_INPROC_SERVER, IID_IActiveDesktop, reinterpret_cast<void **>(&pActiveDesktop))) && pActiveDesktop) {
WALLPAPEROPT opt;
SecureZeroMemory(&opt, sizeof(opt));
opt.dwSize = sizeof(opt);
if (SUCCEEDED(pActiveDesktop->GetWallpaperOptions(&opt, 0))) {
switch (opt.dwStyle) {
case WPSTYLE_CENTER:
return DesktopWallpaperAspectStyle::Central;
case WPSTYLE_TILE:
return DesktopWallpaperAspectStyle::Tiled;
case WPSTYLE_STRETCH:
return DesktopWallpaperAspectStyle::IgnoreRatioFit;
case WPSTYLE_KEEPASPECT:
return DesktopWallpaperAspectStyle::KeepRatioFit;
case WPSTYLE_CROPTOFIT:
return DesktopWallpaperAspectStyle::KeepRatioByExpanding;
case WPSTYLE_SPAN:
return DesktopWallpaperAspectStyle::Span;
}
} else {
qWarning() << "IActiveDesktop::GetWallpaperOptions() failed.";
}
} else {
qWarning() << "Failed to create COM instance - ActiveDesktop.";
}
} else {
qWarning() << "Failed to initialize COM.";
}
qDebug() << "Shell API failed. Reading from the registry instead.";
const QSettings settings(g_desktopRegistryKey, QSettings::NativeFormat);
bool ok = false;
const DWORD style = settings.value(QStringLiteral("WallpaperStyle"), 0).toULongLong(&ok);
if (!ok) {
qWarning() << "Failed to read the registry.";
return DesktopWallpaperAspectStyle::KeepRatioByExpanding; // Fill
}
switch (style) {
case 0: {
bool ok = false;
if ((settings.value(QStringLiteral("TileWallpaper"), 0).toULongLong(&ok) != 0) && ok) {
return DesktopWallpaperAspectStyle::Tiled;
} else {
return DesktopWallpaperAspectStyle::Central;
}
}
case 2:
return DesktopWallpaperAspectStyle::IgnoreRatioFit;
case 6:
return DesktopWallpaperAspectStyle::KeepRatioFit;
case 10:
return DesktopWallpaperAspectStyle::KeepRatioByExpanding;
case 22:
return DesktopWallpaperAspectStyle::Span;
default:
return DesktopWallpaperAspectStyle::KeepRatioByExpanding; // Fill
}
}
quint32 Utilities::getWindowDpi(const QWindow *window)
{
Q_ASSERT(window);
@ -882,58 +454,6 @@ bool Utilities::isWin10OrGreater(const int subVer)
#endif
}
static inline bool forceEnableOfficialMSWin10AcrylicBlur()
{
return qEnvironmentVariableIsSet(_flh_global::_flh_acrylic_forceEnableOfficialMSWin10AcrylicBlur_flag);
}
static inline bool shouldUseOfficialMSWin10AcrylicBlur()
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
const QOperatingSystemVersion currentVersion = QOperatingSystemVersion::current();
if (currentVersion > QOperatingSystemVersion::Windows10) {
return true;
}
return ((currentVersion.microVersion() >= 16190) && (currentVersion.microVersion() < 18362));
#else
// TODO
return false;
#endif
}
bool Utilities::isOfficialMSWin10AcrylicBlurAvailable()
{
if (!isWin10OrGreater()) {
return false;
}
if (!forceEnableTraditionalBlur() && !forceDisableWallpaperBlur() && !disableExtraProcessingForBlur()) {
// We can't enable the official Acrylic blur in wallpaper blur mode.
return false;
}
if (forceEnableOfficialMSWin10AcrylicBlur()) {
return true;
}
return shouldUseOfficialMSWin10AcrylicBlur();
}
static inline bool shouldUseOriginalDwmBlur()
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
return Utilities::isWin10OrGreater() || (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite);
#else
// TODO
return false;
#endif
}
bool Utilities::shouldUseTraditionalBlur()
{
if ((forceEnableTraditionalBlur() || forceDisableWallpaperBlur() || disableExtraProcessingForBlur()) && shouldUseOriginalDwmBlur()) {
return true;
}
return false;
}
void Utilities::displaySystemMenu(const QWindow *window, const QPoint &pos)
{
Q_ASSERT(window);