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 NAMES Qt6 Qt5 COMPONENTS Gui REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} 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 NAMES Qt6 Qt5 COMPONENTS Quick)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick)
set(SOURCES set(SOURCES
qtacrylichelper.qrc
framelesshelper_global.h framelesshelper_global.h
framelesswindowsmanager.h framelesswindowsmanager.h
framelesswindowsmanager.cpp framelesswindowsmanager.cpp
utilities.h utilities.h
utilities.cpp 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) if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
list(APPEND SOURCES list(APPEND SOURCES
framelessquickhelper.h framelessquickhelper.h
framelessquickhelper.cpp framelessquickhelper.cpp
qtacrylicitem.h
qtacrylicitem.cpp
) )
endif() endif()
@ -75,8 +59,6 @@ if(WIN32)
utilities_win32.cpp utilities_win32.cpp
framelesshelper_win32.h framelesshelper_win32.h
framelesshelper_win32.cpp framelesshelper_win32.cpp
qtacryliceffecthelper_win32.h
qtacryliceffecthelper_win32.cpp
) )
else() else()
list(APPEND SOURCES list(APPEND SOURCES
@ -137,12 +119,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::GuiPrivate 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) if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Quick 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). - Support tiled and stack windows by DWM (Win32 only).
- Won't cover the task bar when maximized (Win32 only). - Won't cover the task bar when maximized (Win32 only).
- Won't block the auto-hide 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 ## Usage

View File

@ -10,7 +10,6 @@ TODO
- Draggable. - Draggable.
- Resizable. - 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). - 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. 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. - Support tiled and stack windows by DWM.
- Won't cover the task bar when maximized. - Won't cover the task bar when maximized.
- Won't block the auto-hide 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 ## 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(widget)
add_subdirectory(mainwindow) add_subdirectory(mainwindow)
endif() #endif()
if(TARGET Qt${QT_VERSION_MAJOR}::Quick) if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
add_subdirectory(quick) add_subdirectory(quick)
endif() endif()

View File

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

View File

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

View File

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

View File

@ -28,30 +28,22 @@
#include <QtCore/qdatetime.h> #include <QtCore/qdatetime.h>
#include <QtWidgets/qpushbutton.h> #include <QtWidgets/qpushbutton.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
#include <QtGui/qpainter.h>
#include "../../utilities.h" #include "../../utilities.h"
#include "../../framelesswindowsmanager.h" #include "../../framelesswindowsmanager.h"
Widget::Widget(QWidget *parent) : QtAcrylicWidget(parent) Widget::Widget(QWidget *parent) : QWidget(parent)
{ {
createWinId(); createWinId();
setAcrylicEnabled(true);
setupUi(); setupUi();
startTimer(500); startTimer(500);
} }
Widget::~Widget() = default; 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) void Widget::showEvent(QShowEvent *event)
{ {
QtAcrylicWidget::showEvent(event); QWidget::showEvent(event);
static bool inited = false; static bool inited = false;
if (!inited) { if (!inited) {
FramelessWindowsManager::addWindow(windowHandle()); FramelessWindowsManager::addWindow(windowHandle());
@ -61,13 +53,14 @@ void Widget::showEvent(QShowEvent *event)
void Widget::timerEvent(QTimerEvent *event) void Widget::timerEvent(QTimerEvent *event)
{ {
QtAcrylicWidget::timerEvent(event); QWidget::timerEvent(event);
m_label->setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss"))); m_label->setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss")));
} }
void Widget::changeEvent(QEvent *event) void Widget::changeEvent(QEvent *event)
{ {
QtAcrylicWidget::changeEvent(event); QWidget::changeEvent(event);
bool shouldUpdate = false;
if (event->type() == QEvent::WindowStateChange) { if (event->type() == QEvent::WindowStateChange) {
if (isMaximized() || isFullScreen()) { if (isMaximized() || isFullScreen()) {
layout()->setContentsMargins(0, 0, 0, 0); layout()->setContentsMargins(0, 0, 0, 0);
@ -76,6 +69,37 @@ void Widget::changeEvent(QEvent *event)
layout()->setContentsMargins(1, 1, 1, 1); layout()->setContentsMargins(1, 1, 1, 1);
m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")}); 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 #pragma once
#include "../../qtacrylicwidget.h" #include <QtWidgets/qwidget.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QLabel) QT_FORWARD_DECLARE_CLASS(QLabel)
QT_FORWARD_DECLARE_CLASS(QPushButton) QT_FORWARD_DECLARE_CLASS(QPushButton)
QT_END_NAMESPACE QT_END_NAMESPACE
class Widget : public QtAcrylicWidget class Widget : public QWidget
{ {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY_MOVE(Widget) Q_DISABLE_COPY_MOVE(Widget)
@ -40,12 +40,11 @@ public:
explicit Widget(QWidget *parent = nullptr); explicit Widget(QWidget *parent = nullptr);
~Widget() override; ~Widget() override;
Q_INVOKABLE void moveToDesktopCenter();
protected: protected:
void showEvent(QShowEvent *event) override; void showEvent(QShowEvent *event) override;
void timerEvent(QTimerEvent *event) override; void timerEvent(QTimerEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
void paintEvent(QPaintEvent *event) override;
private: private:
void setupUi(); 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_borderHeight_flag[] = "_FRAMELESSHELPER_WINDOW_BORDER_HEIGHT";
[[maybe_unused]] const char _flh_titleBarHeight_flag[] = "_FRAMELESSHELPER_WINDOW_TITLE_BAR_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_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_useNativeTitleBar_flag[] = "_FRAMELESSHELPER_USE_NATIVE_TITLE_BAR";
[[maybe_unused]] const char _flh_preserveNativeFrame_flag[] = "_FRAMELESSHELPER_PRESERVE_NATIVE_WINDOW_FRAME"; [[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"; [[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. // Fix the flickering issue while resizing.
// "clientRect->right += 1;" also works. // "clientRect->right += 1;" also works.
// The only draw back of this small trick is it will affect // 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 // larger than it should be. Be careful if you need to paint
// something manually either through QPainter or Qt Quick. // something manually either through QPainter or Qt Quick.
clientRect->bottom += 1; clientRect->bottom += 1;
#endif
// If the window bounds change, we're going to relayout and repaint // If the window bounds change, we're going to relayout and repaint
// anyway. Returning WVR_REDRAW avoids an extra paint before that of // anyway. Returning WVR_REDRAW avoids an extra paint before that of
// the old client pixels in the (now wrong) location, and thus makes // 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: default:
break; 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; return false;
} }

View File

@ -29,7 +29,14 @@
FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(parent) 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 int FramelessQuickHelper::borderWidth() const
@ -40,7 +47,7 @@ int FramelessQuickHelper::borderWidth() const
void FramelessQuickHelper::setBorderWidth(const int val) void FramelessQuickHelper::setBorderWidth(const int val)
{ {
FramelessWindowsManager::setBorderWidth(window(), val); FramelessWindowsManager::setBorderWidth(window(), val);
Q_EMIT borderWidthChanged(val); Q_EMIT borderWidthChanged();
} }
int FramelessQuickHelper::borderHeight() const int FramelessQuickHelper::borderHeight() const
@ -51,7 +58,7 @@ int FramelessQuickHelper::borderHeight() const
void FramelessQuickHelper::setBorderHeight(const int val) void FramelessQuickHelper::setBorderHeight(const int val)
{ {
FramelessWindowsManager::setBorderHeight(window(), val); FramelessWindowsManager::setBorderHeight(window(), val);
Q_EMIT borderHeightChanged(val); Q_EMIT borderHeightChanged();
} }
int FramelessQuickHelper::titleBarHeight() const int FramelessQuickHelper::titleBarHeight() const
@ -62,7 +69,7 @@ int FramelessQuickHelper::titleBarHeight() const
void FramelessQuickHelper::setTitleBarHeight(const int val) void FramelessQuickHelper::setTitleBarHeight(const int val)
{ {
FramelessWindowsManager::setTitleBarHeight(window(), val); FramelessWindowsManager::setTitleBarHeight(window(), val);
Q_EMIT titleBarHeightChanged(val); Q_EMIT titleBarHeightChanged();
} }
bool FramelessQuickHelper::resizable() const bool FramelessQuickHelper::resizable() const
@ -73,46 +80,18 @@ bool FramelessQuickHelper::resizable() const
void FramelessQuickHelper::setResizable(const bool val) void FramelessQuickHelper::setResizable(const bool val)
{ {
FramelessWindowsManager::setResizable(window(), 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() void FramelessQuickHelper::removeWindowFrame()
{ {
FramelessWindowsManager::addWindow(window()); FramelessWindowsManager::addWindow(window());
@ -126,22 +105,3 @@ void FramelessQuickHelper::addIgnoreObject(QQuickItem *val)
} }
FramelessWindowsManager::addIgnoreObject(window(), 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_OBJECT
Q_DISABLE_COPY_MOVE(FramelessQuickHelper) Q_DISABLE_COPY_MOVE(FramelessQuickHelper)
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
QML_ELEMENT QML_NAMED_ELEMENT(FramelessHelper)
#endif #endif
Q_PROPERTY(int borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged) Q_PROPERTY(int borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged)
Q_PROPERTY(int borderHeight READ borderHeight WRITE setBorderHeight NOTIFY borderHeightChanged) Q_PROPERTY(int borderHeight READ borderHeight WRITE setBorderHeight NOTIFY borderHeightChanged)
Q_PROPERTY(int titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged) Q_PROPERTY(int titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged)
Q_PROPERTY(bool resizable READ resizable WRITE setResizable NOTIFY resizableChanged) Q_PROPERTY(bool resizable READ resizable WRITE setResizable NOTIFY resizableChanged)
Q_PROPERTY(bool lightThemeEnabled READ lightThemeEnabled NOTIFY lightThemeEnabledChanged) Q_PROPERTY(QColor nativeFrameColor READ nativeFrameColor NOTIFY nativeFrameColorChanged)
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
public: public:
explicit FramelessQuickHelper(QQuickItem *parent = nullptr); explicit FramelessQuickHelper(QQuickItem *parent = nullptr);
@ -64,37 +56,19 @@ public:
bool resizable() const; bool resizable() const;
void setResizable(const bool val); void setResizable(const bool val);
bool lightThemeEnabled() const; QColor nativeFrameColor() const;
bool darkThemeEnabled() const;
#ifdef Q_OS_WINDOWS
bool colorizationEnabled() const;
QColor colorizationColor() const;
bool highContrastModeEnabled() const;
bool darkFrameEnabled() const;
bool transparencyEffectEnabled() const;
#endif
public Q_SLOTS: public Q_SLOTS:
void removeWindowFrame(); void removeWindowFrame();
void addIgnoreObject(QQuickItem *val); void addIgnoreObject(QQuickItem *val);
void setBlurEffectEnabled(const bool enabled = true, const QColor &gradientColor = {});
protected:
void timerEvent(QTimerEvent *event) override;
Q_SIGNALS: Q_SIGNALS:
void borderWidthChanged(int); void borderWidthChanged();
void borderHeightChanged(int); void borderHeightChanged();
void titleBarHeightChanged(int); void titleBarHeightChanged();
void resizableChanged(bool); void resizableChanged();
void lightThemeEnabledChanged(bool); void nativeFrameColorChanged();
void darkThemeEnabledChanged(bool);
#ifdef Q_OS_WINDOWS private:
void colorizationEnabledChanged(bool); QMetaObject::Connection m_frameColorConnection = {};
void colorizationColorChanged(const QColor &);
void highContrastModeEnabledChanged(bool);
void darkFrameEnabledChanged(bool);
void transparencyEffectEnabledChanged(bool);
#endif
}; };

33
lib.pro
View File

@ -15,45 +15,26 @@ HEADERS += \
framelesshelper_global.h \ framelesshelper_global.h \
framelesshelper.h \ framelesshelper.h \
framelesswindowsmanager.h \ framelesswindowsmanager.h \
utilities.h \ utilities.h
qtacryliceffecthelper.h
SOURCES += \ SOURCES += \
framelesshelper.cpp \ framelesshelper.cpp \
framelesswindowsmanager.cpp \ framelesswindowsmanager.cpp \
utilities.cpp \ utilities.cpp
qtacryliceffecthelper.cpp
qtHaveModule(widgets) {
QT += widgets
HEADERS += \
qtacrylicwidget.h \
qtacrylicmainwindow.h
SOURCES += \
qtacrylicwidget.cpp \
qtacrylicmainwindow.cpp
}
qtHaveModule(quick) { qtHaveModule(quick) {
QT += quick QT += quick
HEADERS += \ HEADERS += framelessquickhelper.h
framelessquickhelper.h \ SOURCES += framelessquickhelper.cpp
qtacrylicitem.h
SOURCES += \
framelessquickhelper.cpp \
qtacrylicitem.cpp
} }
RESOURCES += qtacrylichelper.qrc
win32 { win32 {
DEFINES += \ DEFINES += \
WIN32_LEAN_AND_MEAN \ WIN32_LEAN_AND_MEAN \
_CRT_SECURE_NO_WARNINGS \ _CRT_SECURE_NO_WARNINGS \
UNICODE \ UNICODE \
_UNICODE _UNICODE
HEADERS += \ HEADERS += framelesshelper_win32.h
framelesshelper_win32.h \
qtacryliceffecthelper_win32.h
SOURCES += \ SOURCES += \
utilities_win32.cpp \ utilities_win32.cpp \
framelesshelper_win32.cpp \ framelesshelper_win32.cpp
qtacryliceffecthelper_win32.cpp LIBS += -luser32 -lshell32 -lgdi32 -ldwmapi
LIBS += -luser32 -lshell32 -lgdi32 -ldwmapi -lole32
RC_FILE = framelesshelper.rc 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 "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> #include <QtCore/qdebug.h>
#include <QtGui/qguiapplication.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};
}
///////////////////////////////////////////////////
QWindow *Utilities::findWindow(const WId winId) QWindow *Utilities::findWindow(const WId winId)
{ {
@ -380,37 +43,6 @@ QWindow *Utilities::findWindow(const WId winId)
return nullptr; 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() bool Utilities::shouldUseNativeTitleBar()
{ {
return qEnvironmentVariableIsSet(_flh_global::_flh_useNativeTitleBar_flag); return qEnvironmentVariableIsSet(_flh_global::_flh_useNativeTitleBar_flag);
@ -482,36 +114,3 @@ bool Utilities::isMouseInSpecificObjects(const QPointF &mousePos, const QObjectL
} }
return false; 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 TitleBarHeight
}; };
enum class DesktopWallpaperAspectStyle
{
Central,
Tiled,
IgnoreRatioFit, // Stretch
KeepRatioFit, // Fit
KeepRatioByExpanding, // Fill
Span
};
// Common // 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 int getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiAware, const bool forceSystemValue = false);
FRAMELESSHELPER_EXPORT bool isLightThemeEnabled(); FRAMELESSHELPER_EXPORT bool isLightThemeEnabled();
@ -59,30 +45,14 @@ FRAMELESSHELPER_EXPORT bool isDarkThemeEnabled();
FRAMELESSHELPER_EXPORT QWindow *findWindow(const WId winId); 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 shouldUseNativeTitleBar();
FRAMELESSHELPER_EXPORT bool isWindowFixedSize(const QWindow *window); FRAMELESSHELPER_EXPORT bool isWindowFixedSize(const QWindow *window);
FRAMELESSHELPER_EXPORT bool isMouseInSpecificObjects(const QPointF &mousePos, const QObjectList &objects, const qreal dpr = 1.0); 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 #ifdef Q_OS_WINDOWS
// Windows specific // Windows specific
FRAMELESSHELPER_EXPORT bool isWin7OrGreater(); FRAMELESSHELPER_EXPORT bool isWin7OrGreater();
@ -92,22 +62,16 @@ FRAMELESSHELPER_EXPORT bool isWin10OrGreater();
FRAMELESSHELPER_EXPORT bool isWin10OrGreater(const int subVer); FRAMELESSHELPER_EXPORT bool isWin10OrGreater(const int subVer);
FRAMELESSHELPER_EXPORT bool isDwmBlurAvailable(); FRAMELESSHELPER_EXPORT bool isDwmBlurAvailable();
FRAMELESSHELPER_EXPORT bool isOfficialMSWin10AcrylicBlurAvailable();
FRAMELESSHELPER_EXPORT bool isColorizationEnabled(); FRAMELESSHELPER_EXPORT bool isColorizationEnabled();
FRAMELESSHELPER_EXPORT QColor getColorizationColor(); 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 triggerFrameChange(const QWindow *window);
FRAMELESSHELPER_EXPORT void updateFrameMargins(const QWindow *window, const bool reset); FRAMELESSHELPER_EXPORT void updateFrameMargins(const QWindow *window, const bool reset);
FRAMELESSHELPER_EXPORT void updateQtFrameMargins(QWindow *window, const bool enable); FRAMELESSHELPER_EXPORT void updateQtFrameMargins(QWindow *window, const bool enable);
FRAMELESSHELPER_EXPORT quint32 getWindowDpi(const QWindow *window); FRAMELESSHELPER_EXPORT quint32 getWindowDpi(const QWindow *window);
FRAMELESSHELPER_EXPORT QMargins getWindowNativeFrameMargins(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 = {}); FRAMELESSHELPER_EXPORT void displaySystemMenu(const QWindow *window, const QPoint &pos = {});
#endif #endif

View File

@ -36,11 +36,7 @@
#include <QtCore/qt_windows.h> #include <QtCore/qt_windows.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qfileinfo.h>
#include <dwmapi.h> #include <dwmapi.h>
#include <shobjidl_core.h>
#include <wininet.h>
#include <shlobj_core.h>
#include <QtGui/qpa/qplatformwindow.h> #include <QtGui/qpa/qplatformwindow.h>
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
#include <QtGui/qpa/qplatformnativeinterface.h> #include <QtGui/qpa/qplatformnativeinterface.h>
@ -52,9 +48,6 @@
#else #else
#include <QtCore/qsysinfo.h> #include <QtCore/qsysinfo.h>
#endif #endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#include <QtCore/qscopeguard.h>
#endif
Q_DECLARE_METATYPE(QMargins) Q_DECLARE_METATYPE(QMargins)
@ -68,61 +61,8 @@ Q_DECLARE_METATYPE(QMargins)
#define SM_CXPADDEDBORDER 92 #define SM_CXPADDEDBORDER 92
#endif #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_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_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. // 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; 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 PROCESS_PER_MONITOR_DPI_AWARE = 2
}; };
using SetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, WINDOWCOMPOSITIONATTRIBDATA *);
using ShouldAppsUseDarkModePtr = BOOL(WINAPI *)(); 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 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 GetDpiForMonitorPtr = HRESULT(WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *);
using GetProcessDpiAwarenessPtr = HRESULT(WINAPI *)(HANDLE, PROCESS_DPI_AWARENESS *); 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 using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
{ {
_FLH_UTILITIES_WIN32_DATA() { load(); }
SetWindowCompositionAttributePtr SetWindowCompositionAttributePFN = nullptr;
ShouldAppsUseDarkModePtr ShouldAppsUseDarkModePFN = nullptr; ShouldAppsUseDarkModePtr ShouldAppsUseDarkModePFN = nullptr;
AllowDarkModeForWindowPtr AllowDarkModeForWindowPFN = nullptr;
AllowDarkModeForAppPtr AllowDarkModeForAppPFN = nullptr;
IsDarkModeAllowedForWindowPtr IsDarkModeAllowedForWindowPFN = nullptr;
GetIsImmersiveColorUsingHighContrastPtr GetIsImmersiveColorUsingHighContrastPFN = nullptr;
RefreshImmersiveColorPolicyStatePtr RefreshImmersiveColorPolicyStatePFN = nullptr;
ShouldSystemUseDarkModePtr ShouldSystemUseDarkModePFN = nullptr; ShouldSystemUseDarkModePtr ShouldSystemUseDarkModePFN = nullptr;
SetPreferredAppModePtr SetPreferredAppModePFN = nullptr;
IsDarkModeAllowedForAppPtr IsDarkModeAllowedForAppPFN = nullptr;
GetDpiForMonitorPtr GetDpiForMonitorPFN = nullptr; GetDpiForMonitorPtr GetDpiForMonitorPFN = nullptr;
GetProcessDpiAwarenessPtr GetProcessDpiAwarenessPFN = nullptr; GetProcessDpiAwarenessPtr GetProcessDpiAwarenessPFN = nullptr;
@ -181,10 +103,14 @@ using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
GetSystemMetricsForDpiPtr GetSystemMetricsForDpiPFN = nullptr; GetSystemMetricsForDpiPtr GetSystemMetricsForDpiPFN = nullptr;
AdjustWindowRectExForDpiPtr AdjustWindowRectExForDpiPFN = nullptr; AdjustWindowRectExForDpiPtr AdjustWindowRectExForDpiPFN = nullptr;
_FLH_UTILITIES_WIN32_DATA()
{
load();
}
void load() void load()
{ {
QLibrary User32Dll(QStringLiteral("User32")); QLibrary User32Dll(QStringLiteral("User32"));
SetWindowCompositionAttributePFN = reinterpret_cast<SetWindowCompositionAttributePtr>(User32Dll.resolve("SetWindowCompositionAttribute"));
GetDpiForWindowPFN = reinterpret_cast<GetDpiForWindowPtr>(User32Dll.resolve("GetDpiForWindow")); GetDpiForWindowPFN = reinterpret_cast<GetDpiForWindowPtr>(User32Dll.resolve("GetDpiForWindow"));
GetDpiForSystemPFN = reinterpret_cast<GetDpiForSystemPtr>(User32Dll.resolve("GetDpiForSystem")); GetDpiForSystemPFN = reinterpret_cast<GetDpiForSystemPtr>(User32Dll.resolve("GetDpiForSystem"));
GetSystemMetricsForDpiPFN = reinterpret_cast<GetSystemMetricsForDpiPtr>(User32Dll.resolve("GetSystemMetricsForDpi")); GetSystemMetricsForDpiPFN = reinterpret_cast<GetSystemMetricsForDpiPtr>(User32Dll.resolve("GetSystemMetricsForDpi"));
@ -193,14 +119,7 @@ using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
QLibrary UxThemeDll(QStringLiteral("UxTheme")); QLibrary UxThemeDll(QStringLiteral("UxTheme"));
ShouldAppsUseDarkModePFN = reinterpret_cast<ShouldAppsUseDarkModePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(132))); 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))); 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")); QLibrary SHCoreDll(QStringLiteral("SHCore"));
GetDpiForMonitorPFN = reinterpret_cast<GetDpiForMonitorPtr>(SHCoreDll.resolve("GetDpiForMonitor")); GetDpiForMonitorPFN = reinterpret_cast<GetDpiForMonitorPtr>(SHCoreDll.resolve("GetDpiForMonitor"));
@ -294,72 +213,6 @@ int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric,
return ret; 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() bool Utilities::isColorizationEnabled()
{ {
if (!isWin10OrGreater()) { if (!isWin10OrGreater()) {
@ -411,50 +264,6 @@ bool Utilities::isDarkThemeEnabled()
return (ok && !lightThemeEnabled); 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) void Utilities::triggerFrameChange(const QWindow *window)
{ {
Q_ASSERT(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) quint32 Utilities::getWindowDpi(const QWindow *window)
{ {
Q_ASSERT(window); Q_ASSERT(window);
@ -882,58 +454,6 @@ bool Utilities::isWin10OrGreater(const int subVer)
#endif #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) void Utilities::displaySystemMenu(const QWindow *window, const QPoint &pos)
{ {
Q_ASSERT(window); Q_ASSERT(window);