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:
parent
97d9009500
commit
cdb7b87eb4
|
@ -36,37 +36,21 @@ endif()
|
|||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Gui REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Gui REQUIRED)
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets)
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Quick)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick)
|
||||
|
||||
set(SOURCES
|
||||
qtacrylichelper.qrc
|
||||
framelesshelper_global.h
|
||||
framelesswindowsmanager.h
|
||||
framelesswindowsmanager.cpp
|
||||
utilities.h
|
||||
utilities.cpp
|
||||
qtacryliceffecthelper.h
|
||||
qtacryliceffecthelper.cpp
|
||||
)
|
||||
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
list(APPEND SOURCES
|
||||
qtacrylicwidget.h
|
||||
qtacrylicwidget.cpp
|
||||
qtacrylicmainwindow.h
|
||||
qtacrylicmainwindow.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
list(APPEND SOURCES
|
||||
framelessquickhelper.h
|
||||
framelessquickhelper.cpp
|
||||
qtacrylicitem.h
|
||||
qtacrylicitem.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -75,8 +59,6 @@ if(WIN32)
|
|||
utilities_win32.cpp
|
||||
framelesshelper_win32.h
|
||||
framelesshelper_win32.cpp
|
||||
qtacryliceffecthelper_win32.h
|
||||
qtacryliceffecthelper_win32.cpp
|
||||
)
|
||||
else()
|
||||
list(APPEND SOURCES
|
||||
|
@ -137,12 +119,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
|
|||
Qt${QT_VERSION_MAJOR}::GuiPrivate
|
||||
)
|
||||
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
)
|
||||
endif()
|
||||
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Quick
|
||||
|
|
|
@ -19,7 +19,6 @@ If you are using part of or all the code from this repository in your own projec
|
|||
- Support tiled and stack windows by DWM (Win32 only).
|
||||
- Won't cover the task bar when maximized (Win32 only).
|
||||
- Won't block the auto-hide task bar when maximized (Win32 only).
|
||||
- Support cross-platform blur effect inspired by [Microsoft's Acrylic blur](https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic).
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ TODO
|
|||
- Draggable.
|
||||
- Resizable.
|
||||
- Cross-platform: Windows, X11, Wayland, macOS (however, it doesn't look good on Windows, so you may want to try [`FramelessHelperWin`](/framelesshelper_win32.h) instead).
|
||||
- Support blur effect inspired by [Microsoft's Acrylic blur](https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic).
|
||||
|
||||
As for the frame shadow and other window features, they mainly depend on your window manager.
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
- Support tiled and stack windows by DWM.
|
||||
- Won't cover the task bar when maximized.
|
||||
- Won't block the auto-hide task bar when maximized.
|
||||
- Support blur effect inspired by [Microsoft's Acrylic blur](https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic).
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
#if(TARGET Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
add_subdirectory(widget)
|
||||
add_subdirectory(mainwindow)
|
||||
endif()
|
||||
#endif()
|
||||
if(TARGET Qt${QT_VERSION_MAJOR}::Quick)
|
||||
add_subdirectory(quick)
|
||||
endif()
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
*/
|
||||
|
||||
#include "../../framelesswindowsmanager.h"
|
||||
#include "../../qtacrylicmainwindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
#include "ui_TitleBar.h"
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <QtWidgets/qstyleoption.h>
|
||||
#include <QtWidgets/qwidget.h>
|
||||
#include <QtWidgets/qmainwindow.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -56,13 +56,12 @@ int main(int argc, char *argv[])
|
|||
|
||||
QApplication application(argc, argv);
|
||||
|
||||
QtAcrylicMainWindow *mainWindow = new QtAcrylicMainWindow;
|
||||
mainWindow->setAcrylicEnabled(true);
|
||||
const auto mainWindow = new QMainWindow;
|
||||
|
||||
Ui::MainWindow appMainWindow;
|
||||
appMainWindow.setupUi(mainWindow);
|
||||
|
||||
QWidget *widget = new QWidget;
|
||||
const auto widget = new QWidget;
|
||||
Ui::TitleBar titleBarWidget;
|
||||
titleBarWidget.setupUi(widget);
|
||||
|
||||
|
@ -82,11 +81,13 @@ int main(int argc, char *argv[])
|
|||
mainWindow->showMaximized();
|
||||
}
|
||||
});
|
||||
QObject::connect(mainWindow, &QtAcrylicMainWindow::windowStateChanged, [mainWindow, titleBarWidget](){
|
||||
#if 0
|
||||
QObject::connect(mainWindow, &QMainWindow::windowStateChanged, [mainWindow, titleBarWidget](){
|
||||
titleBarWidget.maximizeButton->setChecked(mainWindow->isMaximized());
|
||||
titleBarWidget.maximizeButton->setToolTip(mainWindow->isMaximized() ? QObject::tr("Restore") : QObject::tr("Maximize"));
|
||||
});
|
||||
QObject::connect(titleBarWidget.iconButton, &QPushButton::clicked, mainWindow, &QtAcrylicMainWindow::displaySystemMenu);
|
||||
QObject::connect(titleBarWidget.iconButton, &QPushButton::clicked, mainWindow, &QMainWindow::displaySystemMenu);
|
||||
#endif
|
||||
|
||||
QStyleOption option;
|
||||
option.initFrom(mainWindow);
|
||||
|
@ -105,7 +106,6 @@ int main(int argc, char *argv[])
|
|||
FramelessWindowsManager::addIgnoreObject(win, appMainWindow.menubar);
|
||||
|
||||
mainWindow->resize(800, 600);
|
||||
Q_EMIT mainWindow->windowStateChanged();
|
||||
|
||||
mainWindow->show();
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
*/
|
||||
|
||||
#include "../../framelessquickhelper.h"
|
||||
#include "../../qtacrylicitem.h"
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtQml/qqmlapplicationengine.h>
|
||||
#include <QtQuickControls2/qquickstyle.h>
|
||||
|
@ -65,7 +64,6 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
|
||||
qmlRegisterType<FramelessQuickHelper>("wangwenx190.Utils", 1, 0, "FramelessHelper");
|
||||
qmlRegisterType<QtAcrylicItem>("wangwenx190.Utils", 1, 0, "AcrylicItem");
|
||||
|
||||
const QUrl mainQmlUrl(QStringLiteral("qrc:///qml/main.qml"));
|
||||
const QMetaObject::Connection connection = QObject::connect(
|
||||
|
|
|
@ -33,7 +33,7 @@ Window {
|
|||
width: 800
|
||||
height: 600
|
||||
title: qsTr("Hello, World!")
|
||||
color: "transparent"
|
||||
color: "#f0f0f0"
|
||||
|
||||
property int _flh_margin: ((window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen)) ? 0 : (1 / Screen.devicePixelRatio)
|
||||
|
||||
|
@ -49,13 +49,6 @@ Window {
|
|||
onTriggered: label.text = Qt.formatTime(new Date(), "hh:mm:ss")
|
||||
}
|
||||
|
||||
AcrylicItem {
|
||||
id: acrylicItem
|
||||
anchors.fill: parent
|
||||
acrylicEnabled: true
|
||||
frameVisible: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: titleBar
|
||||
height: framelessHelper.titleBarHeight
|
||||
|
@ -119,8 +112,15 @@ Window {
|
|||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
framelessHelper.removeWindowFrame()
|
||||
framelessHelper.setBlurEffectEnabled(true)
|
||||
Rectangle {
|
||||
id: windowFrame
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border {
|
||||
color: framelessHelper.nativeFrameColor
|
||||
width: window._flh_margin
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: framelessHelper.removeWindowFrame()
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
Widget widget;
|
||||
widget.resize(800, 600);
|
||||
widget.moveToDesktopCenter();
|
||||
widget.show();
|
||||
|
||||
return QApplication::exec();
|
||||
|
|
|
@ -28,30 +28,22 @@
|
|||
#include <QtCore/qdatetime.h>
|
||||
#include <QtWidgets/qpushbutton.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include "../../utilities.h"
|
||||
#include "../../framelesswindowsmanager.h"
|
||||
|
||||
Widget::Widget(QWidget *parent) : QtAcrylicWidget(parent)
|
||||
Widget::Widget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
createWinId();
|
||||
setAcrylicEnabled(true);
|
||||
setupUi();
|
||||
startTimer(500);
|
||||
}
|
||||
|
||||
Widget::~Widget() = default;
|
||||
|
||||
void Widget::moveToDesktopCenter()
|
||||
{
|
||||
const QSize ss = Utilities::getScreenGeometry(nullptr).size();
|
||||
const int newX = (ss.width() - width()) / 2;
|
||||
const int newY = (ss.height() - height()) / 2;
|
||||
move(newX, newY);
|
||||
}
|
||||
|
||||
void Widget::showEvent(QShowEvent *event)
|
||||
{
|
||||
QtAcrylicWidget::showEvent(event);
|
||||
QWidget::showEvent(event);
|
||||
static bool inited = false;
|
||||
if (!inited) {
|
||||
FramelessWindowsManager::addWindow(windowHandle());
|
||||
|
@ -61,13 +53,14 @@ void Widget::showEvent(QShowEvent *event)
|
|||
|
||||
void Widget::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
QtAcrylicWidget::timerEvent(event);
|
||||
QWidget::timerEvent(event);
|
||||
m_label->setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss")));
|
||||
}
|
||||
|
||||
void Widget::changeEvent(QEvent *event)
|
||||
{
|
||||
QtAcrylicWidget::changeEvent(event);
|
||||
QWidget::changeEvent(event);
|
||||
bool shouldUpdate = false;
|
||||
if (event->type() == QEvent::WindowStateChange) {
|
||||
if (isMaximized() || isFullScreen()) {
|
||||
layout()->setContentsMargins(0, 0, 0, 0);
|
||||
|
@ -76,6 +69,37 @@ void Widget::changeEvent(QEvent *event)
|
|||
layout()->setContentsMargins(1, 1, 1, 1);
|
||||
m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")});
|
||||
}
|
||||
shouldUpdate = true;
|
||||
} else if (event->type() == QEvent::ActivationChange) {
|
||||
shouldUpdate = true;
|
||||
}
|
||||
if (shouldUpdate) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QWidget::paintEvent(event);
|
||||
if (windowState() == Qt::WindowNoState) {
|
||||
QPainter painter(this);
|
||||
const int w = width();
|
||||
const int h = height();
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
using BorderLines = QList<QLine>;
|
||||
#else
|
||||
using BorderLines = QVector<QLine>;
|
||||
#endif
|
||||
const BorderLines lines = {
|
||||
{0, 0, w, 0},
|
||||
{w - 1, 0, w - 1, h},
|
||||
{w, h - 1, 0, h - 1},
|
||||
{0, h, 0, 0}
|
||||
};
|
||||
painter.save();
|
||||
painter.setPen({Utilities::getNativeWindowFrameColor(), 1});
|
||||
painter.drawLines(lines);
|
||||
painter.restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,14 +24,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../../qtacrylicwidget.h"
|
||||
#include <QtWidgets/qwidget.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
QT_FORWARD_DECLARE_CLASS(QPushButton)
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Widget : public QtAcrylicWidget
|
||||
class Widget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(Widget)
|
||||
|
@ -40,12 +40,11 @@ public:
|
|||
explicit Widget(QWidget *parent = nullptr);
|
||||
~Widget() override;
|
||||
|
||||
Q_INVOKABLE void moveToDesktopCenter();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
void changeEvent(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
void setupUi();
|
||||
|
|
|
@ -65,13 +65,6 @@ namespace _flh_global {
|
|||
[[maybe_unused]] const char _flh_borderHeight_flag[] = "_FRAMELESSHELPER_WINDOW_BORDER_HEIGHT";
|
||||
[[maybe_unused]] const char _flh_titleBarHeight_flag[] = "_FRAMELESSHELPER_WINDOW_TITLE_BAR_HEIGHT";
|
||||
[[maybe_unused]] const char _flh_ignoredObjects_flag[] = "_FRAMELESSHELPER_WINDOW_TITLE_BAR_IGNORED_OBJECTS";
|
||||
[[maybe_unused]] const char _flh_acrylic_blurEnabled_flag[] = "_FRAMELESSHELPER_BLUR_ENABLED";
|
||||
[[maybe_unused]] const char _flh_acrylic_blurMode_flag[] = "_FRAMELESSHELPER_BLUR_MODE";
|
||||
[[maybe_unused]] const char _flh_acrylic_gradientColor_flag[] = "_FRAMELESSHELPER_BLUR_GRADIENT_COLOR";
|
||||
[[maybe_unused]] const char _flh_acrylic_disableExtraProcess[] = "_FRAMELESSHELPER_DISABLE_EXTRA_PROCESS_FOR_BLUR";
|
||||
[[maybe_unused]] const char _flh_acrylic_forceEnableOfficialMSWin10AcrylicBlur_flag[] = "_FRAMELESSHELPER_FORCE_ENABLE_MSWIN10_OFFICIAL_ACRYLIC_BLUR";
|
||||
[[maybe_unused]] const char _flh_acrylic_forceEnableTraditionalBlur_flag[] = "_FRAMELESSHELPER_FORCE_ENABLE_TRADITIONAL_BLUR";
|
||||
[[maybe_unused]] const char _flh_acrylic_forceDisableWallpaperBlur_flag[] = "_FRAMELESSHELPER_FORCE_DISABLE_WALLPAPER_BLUR";
|
||||
[[maybe_unused]] const char _flh_useNativeTitleBar_flag[] = "_FRAMELESSHELPER_USE_NATIVE_TITLE_BAR";
|
||||
[[maybe_unused]] const char _flh_preserveNativeFrame_flag[] = "_FRAMELESSHELPER_PRESERVE_NATIVE_WINDOW_FRAME";
|
||||
[[maybe_unused]] const char _flh_forcePreserveNativeFrame_flag[] = "_FRAMELESSHELPER_FORCE_PRESERVE_NATIVE_WINDOW_FRAME";
|
||||
|
|
|
@ -412,6 +412,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Fix the flickering issue while resizing.
|
||||
// "clientRect->right += 1;" also works.
|
||||
// The only draw back of this small trick is it will affect
|
||||
|
@ -419,6 +420,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
// larger than it should be. Be careful if you need to paint
|
||||
// something manually either through QPainter or Qt Quick.
|
||||
clientRect->bottom += 1;
|
||||
#endif
|
||||
// If the window bounds change, we're going to relayout and repaint
|
||||
// anyway. Returning WVR_REDRAW avoids an extra paint before that of
|
||||
// the old client pixels in the (now wrong) location, and thus makes
|
||||
|
@ -661,38 +663,6 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
default:
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
// TODO: what if the user want to use the wallpaper blur all the time?
|
||||
// Add an option to let the user choose what he wants.
|
||||
if (Utilities::isWin10OrGreater()) {
|
||||
if (window->property(_flh_global::_flh_acrylic_blurEnabled_flag).toBool()) {
|
||||
bool shouldSwitchBlurMode = false;
|
||||
if (msg->message == WM_ENTERSIZEMOVE) {
|
||||
shouldSwitchBlurMode = true;
|
||||
// Switch to the wallpaper blur temporarily due to the following issue:
|
||||
// the window will become **VERY** laggy when it's being moved or resized.
|
||||
// It's known as a bug of the API itself, currently no one knows how to fix it.
|
||||
qunsetenv(_flh_global::_flh_acrylic_forceDisableWallpaperBlur_flag);
|
||||
qunsetenv(_flh_global::_flh_acrylic_forceEnableTraditionalBlur_flag);
|
||||
qunsetenv(_flh_global::_flh_acrylic_forceEnableOfficialMSWin10AcrylicBlur_flag);
|
||||
}
|
||||
if (msg->message == WM_EXITSIZEMOVE) {
|
||||
shouldSwitchBlurMode = true;
|
||||
// Switch back to the official Acrylic blur. That undocumented API won't cause any issues
|
||||
// if we don't move or resize the window.
|
||||
qputenv(_flh_global::_flh_acrylic_forceEnableTraditionalBlur_flag, "True");
|
||||
qputenv(_flh_global::_flh_acrylic_forceDisableWallpaperBlur_flag, "True");
|
||||
qputenv(_flh_global::_flh_acrylic_forceEnableOfficialMSWin10AcrylicBlur_flag, "True");
|
||||
}
|
||||
if (shouldSwitchBlurMode) {
|
||||
const auto gradientColor = qvariant_cast<QColor>(window->property(_flh_global::_flh_acrylic_gradientColor_flag));
|
||||
if (!Utilities::setBlurEffectEnabled(window, true, gradientColor)) {
|
||||
qWarning() << "Failed to enable the blur effect.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,14 @@
|
|||
|
||||
FramelessQuickHelper::FramelessQuickHelper(QQuickItem *parent) : QQuickItem(parent)
|
||||
{
|
||||
startTimer(500);
|
||||
connect(this, &FramelessQuickHelper::windowChanged, this, [this](QQuickWindow *win){
|
||||
if (m_frameColorConnection) {
|
||||
disconnect(m_frameColorConnection);
|
||||
}
|
||||
if (win) {
|
||||
m_frameColorConnection = connect(win, &QQuickWindow::activeChanged, this, &FramelessQuickHelper::nativeFrameColorChanged);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int FramelessQuickHelper::borderWidth() const
|
||||
|
@ -40,7 +47,7 @@ int FramelessQuickHelper::borderWidth() const
|
|||
void FramelessQuickHelper::setBorderWidth(const int val)
|
||||
{
|
||||
FramelessWindowsManager::setBorderWidth(window(), val);
|
||||
Q_EMIT borderWidthChanged(val);
|
||||
Q_EMIT borderWidthChanged();
|
||||
}
|
||||
|
||||
int FramelessQuickHelper::borderHeight() const
|
||||
|
@ -51,7 +58,7 @@ int FramelessQuickHelper::borderHeight() const
|
|||
void FramelessQuickHelper::setBorderHeight(const int val)
|
||||
{
|
||||
FramelessWindowsManager::setBorderHeight(window(), val);
|
||||
Q_EMIT borderHeightChanged(val);
|
||||
Q_EMIT borderHeightChanged();
|
||||
}
|
||||
|
||||
int FramelessQuickHelper::titleBarHeight() const
|
||||
|
@ -62,7 +69,7 @@ int FramelessQuickHelper::titleBarHeight() const
|
|||
void FramelessQuickHelper::setTitleBarHeight(const int val)
|
||||
{
|
||||
FramelessWindowsManager::setTitleBarHeight(window(), val);
|
||||
Q_EMIT titleBarHeightChanged(val);
|
||||
Q_EMIT titleBarHeightChanged();
|
||||
}
|
||||
|
||||
bool FramelessQuickHelper::resizable() const
|
||||
|
@ -73,46 +80,18 @@ bool FramelessQuickHelper::resizable() const
|
|||
void FramelessQuickHelper::setResizable(const bool val)
|
||||
{
|
||||
FramelessWindowsManager::setResizable(window(), val);
|
||||
Q_EMIT resizableChanged(val);
|
||||
Q_EMIT resizableChanged();
|
||||
}
|
||||
|
||||
bool FramelessQuickHelper::lightThemeEnabled() const
|
||||
QColor FramelessQuickHelper::nativeFrameColor() const
|
||||
{
|
||||
return Utilities::isLightThemeEnabled();
|
||||
const auto win = window();
|
||||
if (!win) {
|
||||
return Qt::black;
|
||||
}
|
||||
return Utilities::getNativeWindowFrameColor(win->isActive());
|
||||
}
|
||||
|
||||
bool FramelessQuickHelper::darkThemeEnabled() const
|
||||
{
|
||||
return Utilities::isDarkThemeEnabled();
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
bool FramelessQuickHelper::colorizationEnabled() const
|
||||
{
|
||||
return Utilities::isColorizationEnabled();
|
||||
}
|
||||
|
||||
QColor FramelessQuickHelper::colorizationColor() const
|
||||
{
|
||||
return Utilities::getColorizationColor();
|
||||
}
|
||||
|
||||
bool FramelessQuickHelper::highContrastModeEnabled() const
|
||||
{
|
||||
return Utilities::isHighContrastModeEnabled();
|
||||
}
|
||||
|
||||
bool FramelessQuickHelper::darkFrameEnabled() const
|
||||
{
|
||||
return Utilities::isDarkFrameEnabled(window());
|
||||
}
|
||||
|
||||
bool FramelessQuickHelper::transparencyEffectEnabled() const
|
||||
{
|
||||
return Utilities::isTransparencyEffectEnabled();
|
||||
}
|
||||
#endif
|
||||
|
||||
void FramelessQuickHelper::removeWindowFrame()
|
||||
{
|
||||
FramelessWindowsManager::addWindow(window());
|
||||
|
@ -126,22 +105,3 @@ void FramelessQuickHelper::addIgnoreObject(QQuickItem *val)
|
|||
}
|
||||
FramelessWindowsManager::addIgnoreObject(window(), val);
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
QQuickItem::timerEvent(event);
|
||||
Q_EMIT lightThemeEnabledChanged(lightThemeEnabled());
|
||||
Q_EMIT darkThemeEnabledChanged(darkThemeEnabled());
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Q_EMIT colorizationEnabledChanged(colorizationEnabled());
|
||||
Q_EMIT colorizationColorChanged(colorizationColor());
|
||||
Q_EMIT highContrastModeEnabledChanged(highContrastModeEnabled());
|
||||
Q_EMIT darkFrameEnabledChanged(darkFrameEnabled());
|
||||
Q_EMIT transparencyEffectEnabledChanged(transparencyEffectEnabled());
|
||||
#endif
|
||||
}
|
||||
|
||||
void FramelessQuickHelper::setBlurEffectEnabled(const bool enabled, const QColor &gradientColor)
|
||||
{
|
||||
Utilities::setBlurEffectEnabled(window(), enabled, gradientColor);
|
||||
}
|
||||
|
|
|
@ -32,21 +32,13 @@ class FRAMELESSHELPER_EXPORT FramelessQuickHelper : public QQuickItem
|
|||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(FramelessQuickHelper)
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
QML_ELEMENT
|
||||
QML_NAMED_ELEMENT(FramelessHelper)
|
||||
#endif
|
||||
Q_PROPERTY(int borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged)
|
||||
Q_PROPERTY(int borderHeight READ borderHeight WRITE setBorderHeight NOTIFY borderHeightChanged)
|
||||
Q_PROPERTY(int titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged)
|
||||
Q_PROPERTY(bool resizable READ resizable WRITE setResizable NOTIFY resizableChanged)
|
||||
Q_PROPERTY(bool lightThemeEnabled READ lightThemeEnabled NOTIFY lightThemeEnabledChanged)
|
||||
Q_PROPERTY(bool darkThemeEnabled READ darkThemeEnabled NOTIFY darkThemeEnabledChanged)
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Q_PROPERTY(bool colorizationEnabled READ colorizationEnabled NOTIFY colorizationEnabledChanged)
|
||||
Q_PROPERTY(QColor colorizationColor READ colorizationColor NOTIFY colorizationColorChanged)
|
||||
Q_PROPERTY(bool highContrastModeEnabled READ highContrastModeEnabled NOTIFY highContrastModeEnabledChanged)
|
||||
Q_PROPERTY(bool darkFrameEnabled READ darkFrameEnabled NOTIFY darkFrameEnabledChanged)
|
||||
Q_PROPERTY(bool transparencyEffectEnabled READ transparencyEffectEnabled NOTIFY transparencyEffectEnabledChanged)
|
||||
#endif
|
||||
Q_PROPERTY(QColor nativeFrameColor READ nativeFrameColor NOTIFY nativeFrameColorChanged)
|
||||
|
||||
public:
|
||||
explicit FramelessQuickHelper(QQuickItem *parent = nullptr);
|
||||
|
@ -64,37 +56,19 @@ public:
|
|||
bool resizable() const;
|
||||
void setResizable(const bool val);
|
||||
|
||||
bool lightThemeEnabled() const;
|
||||
bool darkThemeEnabled() const;
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
bool colorizationEnabled() const;
|
||||
QColor colorizationColor() const;
|
||||
bool highContrastModeEnabled() const;
|
||||
bool darkFrameEnabled() const;
|
||||
bool transparencyEffectEnabled() const;
|
||||
#endif
|
||||
QColor nativeFrameColor() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void removeWindowFrame();
|
||||
void addIgnoreObject(QQuickItem *val);
|
||||
void setBlurEffectEnabled(const bool enabled = true, const QColor &gradientColor = {});
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void borderWidthChanged(int);
|
||||
void borderHeightChanged(int);
|
||||
void titleBarHeightChanged(int);
|
||||
void resizableChanged(bool);
|
||||
void lightThemeEnabledChanged(bool);
|
||||
void darkThemeEnabledChanged(bool);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
void colorizationEnabledChanged(bool);
|
||||
void colorizationColorChanged(const QColor &);
|
||||
void highContrastModeEnabledChanged(bool);
|
||||
void darkFrameEnabledChanged(bool);
|
||||
void transparencyEffectEnabledChanged(bool);
|
||||
#endif
|
||||
void borderWidthChanged();
|
||||
void borderHeightChanged();
|
||||
void titleBarHeightChanged();
|
||||
void resizableChanged();
|
||||
void nativeFrameColorChanged();
|
||||
|
||||
private:
|
||||
QMetaObject::Connection m_frameColorConnection = {};
|
||||
};
|
||||
|
|
33
lib.pro
33
lib.pro
|
@ -15,45 +15,26 @@ HEADERS += \
|
|||
framelesshelper_global.h \
|
||||
framelesshelper.h \
|
||||
framelesswindowsmanager.h \
|
||||
utilities.h \
|
||||
qtacryliceffecthelper.h
|
||||
utilities.h
|
||||
SOURCES += \
|
||||
framelesshelper.cpp \
|
||||
framelesswindowsmanager.cpp \
|
||||
utilities.cpp \
|
||||
qtacryliceffecthelper.cpp
|
||||
qtHaveModule(widgets) {
|
||||
QT += widgets
|
||||
HEADERS += \
|
||||
qtacrylicwidget.h \
|
||||
qtacrylicmainwindow.h
|
||||
SOURCES += \
|
||||
qtacrylicwidget.cpp \
|
||||
qtacrylicmainwindow.cpp
|
||||
}
|
||||
utilities.cpp
|
||||
qtHaveModule(quick) {
|
||||
QT += quick
|
||||
HEADERS += \
|
||||
framelessquickhelper.h \
|
||||
qtacrylicitem.h
|
||||
SOURCES += \
|
||||
framelessquickhelper.cpp \
|
||||
qtacrylicitem.cpp
|
||||
HEADERS += framelessquickhelper.h
|
||||
SOURCES += framelessquickhelper.cpp
|
||||
}
|
||||
RESOURCES += qtacrylichelper.qrc
|
||||
win32 {
|
||||
DEFINES += \
|
||||
WIN32_LEAN_AND_MEAN \
|
||||
_CRT_SECURE_NO_WARNINGS \
|
||||
UNICODE \
|
||||
_UNICODE
|
||||
HEADERS += \
|
||||
framelesshelper_win32.h \
|
||||
qtacryliceffecthelper_win32.h
|
||||
HEADERS += framelesshelper_win32.h
|
||||
SOURCES += \
|
||||
utilities_win32.cpp \
|
||||
framelesshelper_win32.cpp \
|
||||
qtacryliceffecthelper_win32.cpp
|
||||
LIBS += -luser32 -lshell32 -lgdi32 -ldwmapi -lole32
|
||||
framelesshelper_win32.cpp
|
||||
LIBS += -luser32 -lshell32 -lgdi32 -ldwmapi
|
||||
RC_FILE = framelesshelper.rc
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
<RCC>
|
||||
<qresource prefix="/QtAcrylicHelper">
|
||||
<file alias="Noise.png">resources/noise.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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 |
403
utilities.cpp
403
utilities.cpp
|
@ -23,345 +23,8 @@
|
|||
*/
|
||||
|
||||
#include "utilities.h"
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include <QtGui/private/qmemrotate_p.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
/*
|
||||
* Copied from https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/effects/qpixmapfilter.cpp
|
||||
* With minor modifications, most of them are format changes.
|
||||
* They are exported functions of Qt, we can make use of them directly, but they are in the QtWidgets
|
||||
* module, I don't want our library have such a dependency.
|
||||
*/
|
||||
|
||||
#ifndef AVG
|
||||
#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
|
||||
#endif
|
||||
|
||||
#ifndef AVG16
|
||||
#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
|
||||
#endif
|
||||
|
||||
template<const int shift>
|
||||
static inline int qt_static_shift(const int value)
|
||||
{
|
||||
if (shift == 0) {
|
||||
return value;
|
||||
} else if (shift > 0) {
|
||||
return value << (uint(shift) & 0x1f);
|
||||
} else {
|
||||
return value >> (uint(-shift) & 0x1f);
|
||||
}
|
||||
}
|
||||
|
||||
template<const int aprec, const int zprec>
|
||||
static inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, const int alpha)
|
||||
{
|
||||
QRgb *pixel = reinterpret_cast<QRgb *>(bptr);
|
||||
#define Z_MASK (0xff << zprec)
|
||||
const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
|
||||
const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
|
||||
const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
|
||||
const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
|
||||
#undef Z_MASK
|
||||
const int zR_zprec = zR >> aprec;
|
||||
const int zG_zprec = zG >> aprec;
|
||||
const int zB_zprec = zB >> aprec;
|
||||
const int zA_zprec = zA >> aprec;
|
||||
zR += alpha * (R_zprec - zR_zprec);
|
||||
zG += alpha * (G_zprec - zG_zprec);
|
||||
zB += alpha * (B_zprec - zB_zprec);
|
||||
zA += alpha * (A_zprec - zA_zprec);
|
||||
#define ZA_MASK (0xff << (zprec + aprec))
|
||||
*pixel =
|
||||
qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
|
||||
| qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
|
||||
| qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
|
||||
| qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
|
||||
#undef ZA_MASK
|
||||
}
|
||||
|
||||
static const int alphaIndex = ((QSysInfo::ByteOrder == QSysInfo::BigEndian) ? 0 : 3);
|
||||
|
||||
template<const int aprec, const int zprec>
|
||||
static inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, const int alpha)
|
||||
{
|
||||
const int A_zprec = int(*(bptr)) << zprec;
|
||||
const int z_zprec = z >> aprec;
|
||||
z += alpha * (A_zprec - z_zprec);
|
||||
*(bptr) = z >> (zprec + aprec);
|
||||
}
|
||||
|
||||
template<const int aprec, const int zprec, const bool alphaOnly>
|
||||
static inline void qt_blurrow(QImage &im, const int line, const int alpha)
|
||||
{
|
||||
uchar *bptr = im.scanLine(line);
|
||||
int zR = 0, zG = 0, zB = 0, zA = 0;
|
||||
if (alphaOnly && (im.format() != QImage::Format_Indexed8)) {
|
||||
bptr += alphaIndex;
|
||||
}
|
||||
const int stride = im.depth() >> 3;
|
||||
const int im_width = im.width();
|
||||
for (int index = 0; index < im_width; ++index) {
|
||||
if (alphaOnly) {
|
||||
qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
|
||||
} else {
|
||||
qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
|
||||
}
|
||||
bptr += stride;
|
||||
}
|
||||
bptr -= stride;
|
||||
for (int index = im_width - 2; index >= 0; --index) {
|
||||
bptr -= stride;
|
||||
if (alphaOnly) {
|
||||
qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
|
||||
} else {
|
||||
qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* expblur(QImage &img, const qreal radius)
|
||||
*
|
||||
* Based on exponential blur algorithm by Jani Huhtanen
|
||||
*
|
||||
* In-place blur of image 'img' with kernel
|
||||
* of approximate radius 'radius'.
|
||||
*
|
||||
* Blurs with two sided exponential impulse
|
||||
* response.
|
||||
*
|
||||
* aprec = precision of alpha parameter
|
||||
* in fixed-point format 0.aprec
|
||||
*
|
||||
* zprec = precision of state parameters
|
||||
* zR,zG,zB and zA in fp format 8.zprec
|
||||
*/
|
||||
template<const int aprec, const int zprec, const bool alphaOnly>
|
||||
static inline void expblur(QImage &img, const qreal radius, const bool improvedQuality = false, const int transposed = 0)
|
||||
{
|
||||
qreal _radius = radius;
|
||||
// halve the radius if we're using two passes
|
||||
if (improvedQuality) {
|
||||
_radius *= 0.5;
|
||||
}
|
||||
Q_ASSERT((img.format() == QImage::Format_ARGB32_Premultiplied)
|
||||
|| (img.format() == QImage::Format_RGB32)
|
||||
|| (img.format() == QImage::Format_Indexed8)
|
||||
|| (img.format() == QImage::Format_Grayscale8));
|
||||
// choose the alpha such that pixels at radius distance from a fully
|
||||
// saturated pixel will have an alpha component of no greater than
|
||||
// the cutOffIntensity
|
||||
const qreal cutOffIntensity = 2;
|
||||
const int alpha = _radius <= qreal(1e-5)
|
||||
? ((1 << aprec)-1)
|
||||
: qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / _radius)));
|
||||
int img_height = img.height();
|
||||
for (int row = 0; row < img_height; ++row) {
|
||||
for (int i = 0; i <= int(improvedQuality); ++i) {
|
||||
qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
|
||||
}
|
||||
}
|
||||
// TODO: QImage(int width, int height, QImage::Format format)
|
||||
// Why the argument order is inverted here? The application will crash if change it back.
|
||||
QImage temp(img.height(), img.width(), img.format());
|
||||
temp.setDevicePixelRatio(img.devicePixelRatio());
|
||||
if (transposed >= 0) {
|
||||
if (img.depth() == 8) {
|
||||
qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
|
||||
img.width(), img.height(), img.bytesPerLine(),
|
||||
reinterpret_cast<quint8*>(temp.bits()),
|
||||
temp.bytesPerLine());
|
||||
} else {
|
||||
qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
|
||||
img.width(), img.height(), img.bytesPerLine(),
|
||||
reinterpret_cast<quint32*>(temp.bits()),
|
||||
temp.bytesPerLine());
|
||||
}
|
||||
} else {
|
||||
if (img.depth() == 8) {
|
||||
qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
|
||||
img.width(), img.height(), img.bytesPerLine(),
|
||||
reinterpret_cast<quint8*>(temp.bits()),
|
||||
temp.bytesPerLine());
|
||||
} else {
|
||||
qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
|
||||
img.width(), img.height(), img.bytesPerLine(),
|
||||
reinterpret_cast<quint32*>(temp.bits()),
|
||||
temp.bytesPerLine());
|
||||
}
|
||||
}
|
||||
img_height = temp.height();
|
||||
for (int row = 0; row < img_height; ++row) {
|
||||
for (int i = 0; i <= int(improvedQuality); ++i) {
|
||||
qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
|
||||
}
|
||||
}
|
||||
if (transposed == 0) {
|
||||
if (img.depth() == 8) {
|
||||
qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
|
||||
temp.width(), temp.height(), temp.bytesPerLine(),
|
||||
reinterpret_cast<quint8*>(img.bits()),
|
||||
img.bytesPerLine());
|
||||
} else {
|
||||
qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
|
||||
temp.width(), temp.height(), temp.bytesPerLine(),
|
||||
reinterpret_cast<quint32*>(img.bits()),
|
||||
img.bytesPerLine());
|
||||
}
|
||||
} else {
|
||||
img = temp;
|
||||
}
|
||||
}
|
||||
|
||||
static inline QImage qt_halfScaled(const QImage &source)
|
||||
{
|
||||
if (source.width() < 2 || source.height() < 2) {
|
||||
return {};
|
||||
}
|
||||
QImage srcImage = source;
|
||||
if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
|
||||
// assumes grayscale
|
||||
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
|
||||
dest.setDevicePixelRatio(source.devicePixelRatio());
|
||||
const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
|
||||
qsizetype sx = srcImage.bytesPerLine();
|
||||
qsizetype sx2 = sx << 1;
|
||||
uchar *dst = reinterpret_cast<uchar*>(dest.bits());
|
||||
qsizetype dx = dest.bytesPerLine();
|
||||
int ww = dest.width();
|
||||
int hh = dest.height();
|
||||
for (int y = hh; y; --y, dst += dx, src += sx2) {
|
||||
const uchar *p1 = src;
|
||||
const uchar *p2 = src + sx;
|
||||
uchar *q = dst;
|
||||
for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2) {
|
||||
*q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
} else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
|
||||
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
|
||||
dest.setDevicePixelRatio(source.devicePixelRatio());
|
||||
const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
|
||||
qsizetype sx = srcImage.bytesPerLine();
|
||||
qsizetype sx2 = sx << 1;
|
||||
uchar *dst = reinterpret_cast<uchar*>(dest.bits());
|
||||
qsizetype dx = dest.bytesPerLine();
|
||||
int ww = dest.width();
|
||||
int hh = dest.height();
|
||||
for (int y = hh; y; --y, dst += dx, src += sx2) {
|
||||
const uchar *p1 = src;
|
||||
const uchar *p2 = src + sx;
|
||||
uchar *q = dst;
|
||||
for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
|
||||
// alpha
|
||||
q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
|
||||
// rgb
|
||||
const quint16 p16_1 = (p1[2] << 8) | p1[1];
|
||||
const quint16 p16_2 = (p1[5] << 8) | p1[4];
|
||||
const quint16 p16_3 = (p2[2] << 8) | p2[1];
|
||||
const quint16 p16_4 = (p2[5] << 8) | p2[4];
|
||||
const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
|
||||
q[1] = result & 0xff;
|
||||
q[2] = result >> 8;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
} else if ((source.format() != QImage::Format_ARGB32_Premultiplied) && (source.format() != QImage::Format_RGB32)) {
|
||||
srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
|
||||
dest.setDevicePixelRatio(source.devicePixelRatio());
|
||||
const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
|
||||
qsizetype sx = srcImage.bytesPerLine() >> 2;
|
||||
qsizetype sx2 = sx << 1;
|
||||
quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
|
||||
qsizetype dx = dest.bytesPerLine() >> 2;
|
||||
int ww = dest.width();
|
||||
int hh = dest.height();
|
||||
for (int y = hh; y; --y, dst += dx, src += sx2) {
|
||||
const quint32 *p1 = src;
|
||||
const quint32 *p2 = src + sx;
|
||||
quint32 *q = dst;
|
||||
for (int x = ww; x; --x, q++, p1 += 2, p2 += 2) {
|
||||
*q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
void Utilities::blurImage(QPainter *painter, QImage &blurImage, const qreal radius, const bool quality, const bool alphaOnly, const int transposed)
|
||||
{
|
||||
if ((blurImage.format() != QImage::Format_ARGB32_Premultiplied) && (blurImage.format() != QImage::Format_RGB32)) {
|
||||
blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
qreal _radius = radius;
|
||||
qreal scale = 1;
|
||||
if ((_radius >= 4) && (blurImage.width() >= 2) && (blurImage.height() >= 2)) {
|
||||
blurImage = qt_halfScaled(blurImage);
|
||||
scale = 2;
|
||||
_radius *= 0.5;
|
||||
}
|
||||
if (alphaOnly) {
|
||||
expblur<12, 10, true>(blurImage, _radius, quality, transposed);
|
||||
} else {
|
||||
expblur<12, 10, false>(blurImage, _radius, quality, transposed);
|
||||
}
|
||||
if (painter) {
|
||||
painter->scale(scale, scale);
|
||||
painter->setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter->drawImage(QRect{QPoint{0, 0}, blurImage.size() / blurImage.devicePixelRatio()}, blurImage);
|
||||
}
|
||||
}
|
||||
|
||||
void Utilities::blurImage(QImage &blurImage, const qreal radius, const bool quality, const int transposed)
|
||||
{
|
||||
if ((blurImage.format() == QImage::Format_Indexed8) || (blurImage.format() == QImage::Format_Grayscale8)) {
|
||||
expblur<12, 10, true>(blurImage, radius, quality, transposed);
|
||||
} else {
|
||||
expblur<12, 10, false>(blurImage, radius, quality, transposed);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* Copied from https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/styles/qstyle.cpp
|
||||
* With minor modifications, most of them are format changes.
|
||||
* They are exported functions of Qt, we can make use of them directly, but they are in the QtWidgets
|
||||
* module, I don't want our library have such a dependency.
|
||||
*/
|
||||
|
||||
static inline Qt::Alignment visualAlignment(const Qt::LayoutDirection direction, const Qt::Alignment alignment)
|
||||
{
|
||||
return QGuiApplicationPrivate::visualAlignment(direction, alignment);
|
||||
}
|
||||
|
||||
QRect Utilities::alignedRect(const Qt::LayoutDirection direction, const Qt::Alignment alignment, const QSize &size, const QRect &rectangle)
|
||||
{
|
||||
const Qt::Alignment align = visualAlignment(direction, alignment);
|
||||
int x = rectangle.x();
|
||||
int y = rectangle.y();
|
||||
const int w = size.width();
|
||||
const int h = size.height();
|
||||
if ((align & Qt::AlignVCenter) == Qt::AlignVCenter) {
|
||||
y += rectangle.size().height() / 2 - h / 2;
|
||||
} else if ((align & Qt::AlignBottom) == Qt::AlignBottom) {
|
||||
y += rectangle.size().height() - h;
|
||||
}
|
||||
if ((align & Qt::AlignRight) == Qt::AlignRight) {
|
||||
x += rectangle.size().width() - w;
|
||||
} else if ((align & Qt::AlignHCenter) == Qt::AlignHCenter) {
|
||||
x += rectangle.size().width() / 2 - w / 2;
|
||||
}
|
||||
return {x, y, w, h};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
#include <QtGui/qguiapplication.h>
|
||||
|
||||
QWindow *Utilities::findWindow(const WId winId)
|
||||
{
|
||||
|
@ -380,37 +43,6 @@ QWindow *Utilities::findWindow(const WId winId)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
QRect Utilities::getScreenAvailableGeometry(const QWindow *window)
|
||||
{
|
||||
if (window) {
|
||||
const QScreen *screen = window->screen();
|
||||
if (screen) {
|
||||
return screen->availableGeometry();
|
||||
}
|
||||
}
|
||||
return QGuiApplication::primaryScreen()->availableGeometry();
|
||||
}
|
||||
|
||||
bool Utilities::shouldUseWallpaperBlur()
|
||||
{
|
||||
return !shouldUseTraditionalBlur();
|
||||
}
|
||||
|
||||
bool Utilities::disableExtraProcessingForBlur()
|
||||
{
|
||||
return qEnvironmentVariableIsSet(_flh_global::_flh_acrylic_disableExtraProcess);
|
||||
}
|
||||
|
||||
bool Utilities::forceEnableTraditionalBlur()
|
||||
{
|
||||
return qEnvironmentVariableIsSet(_flh_global::_flh_acrylic_forceEnableTraditionalBlur_flag);
|
||||
}
|
||||
|
||||
bool Utilities::forceDisableWallpaperBlur()
|
||||
{
|
||||
return qEnvironmentVariableIsSet(_flh_global::_flh_acrylic_forceDisableWallpaperBlur_flag);
|
||||
}
|
||||
|
||||
bool Utilities::shouldUseNativeTitleBar()
|
||||
{
|
||||
return qEnvironmentVariableIsSet(_flh_global::_flh_useNativeTitleBar_flag);
|
||||
|
@ -482,36 +114,3 @@ bool Utilities::isMouseInSpecificObjects(const QPointF &mousePos, const QObjectL
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QRect Utilities::getScreenAvailableGeometry(const QPoint &pos)
|
||||
{
|
||||
if (!pos.isNull()) {
|
||||
const QScreen *screen = QGuiApplication::screenAt(pos);
|
||||
if (screen) {
|
||||
return screen->availableGeometry();
|
||||
}
|
||||
}
|
||||
return QGuiApplication::primaryScreen()->availableGeometry();
|
||||
}
|
||||
|
||||
QRect Utilities::getScreenGeometry(const QWindow *window)
|
||||
{
|
||||
if (window) {
|
||||
const QScreen *screen = window->screen();
|
||||
if (screen) {
|
||||
return screen->geometry();
|
||||
}
|
||||
}
|
||||
return QGuiApplication::primaryScreen()->geometry();
|
||||
}
|
||||
|
||||
QRect Utilities::getScreenGeometry(const QPoint &pos)
|
||||
{
|
||||
if (!pos.isNull()) {
|
||||
const QScreen *screen = QGuiApplication::screenAt(pos);
|
||||
if (screen) {
|
||||
return screen->geometry();
|
||||
}
|
||||
}
|
||||
return QGuiApplication::primaryScreen()->geometry();
|
||||
}
|
||||
|
|
40
utilities.h
40
utilities.h
|
@ -37,21 +37,7 @@ enum class SystemMetric
|
|||
TitleBarHeight
|
||||
};
|
||||
|
||||
enum class DesktopWallpaperAspectStyle
|
||||
{
|
||||
Central,
|
||||
Tiled,
|
||||
IgnoreRatioFit, // Stretch
|
||||
KeepRatioFit, // Fit
|
||||
KeepRatioByExpanding, // Fill
|
||||
Span
|
||||
};
|
||||
|
||||
// Common
|
||||
FRAMELESSHELPER_EXPORT bool shouldUseWallpaperBlur();
|
||||
FRAMELESSHELPER_EXPORT bool shouldUseTraditionalBlur();
|
||||
FRAMELESSHELPER_EXPORT bool setBlurEffectEnabled(const QWindow *window, const bool enabled, const QColor &gradientColor = {});
|
||||
|
||||
FRAMELESSHELPER_EXPORT int getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiAware, const bool forceSystemValue = false);
|
||||
|
||||
FRAMELESSHELPER_EXPORT bool isLightThemeEnabled();
|
||||
|
@ -59,30 +45,14 @@ FRAMELESSHELPER_EXPORT bool isDarkThemeEnabled();
|
|||
|
||||
FRAMELESSHELPER_EXPORT QWindow *findWindow(const WId winId);
|
||||
|
||||
FRAMELESSHELPER_EXPORT QImage getDesktopWallpaperImage(const int screen = -1);
|
||||
FRAMELESSHELPER_EXPORT QColor getDesktopBackgroundColor(const int screen = -1);
|
||||
FRAMELESSHELPER_EXPORT DesktopWallpaperAspectStyle getDesktopWallpaperAspectStyle(const int screen = -1);
|
||||
|
||||
FRAMELESSHELPER_EXPORT QRect getScreenAvailableGeometry(const QWindow *window);
|
||||
FRAMELESSHELPER_EXPORT QRect getScreenAvailableGeometry(const QPoint &pos);
|
||||
|
||||
FRAMELESSHELPER_EXPORT QRect getScreenGeometry(const QWindow *window);
|
||||
FRAMELESSHELPER_EXPORT QRect getScreenGeometry(const QPoint &pos);
|
||||
|
||||
FRAMELESSHELPER_EXPORT QRect alignedRect(const Qt::LayoutDirection direction, const Qt::Alignment alignment, const QSize &size, const QRect &rectangle);
|
||||
|
||||
FRAMELESSHELPER_EXPORT void blurImage(QImage &blurImage, const qreal radius, const bool quality, const int transposed = 0);
|
||||
FRAMELESSHELPER_EXPORT void blurImage(QPainter *painter, QImage &blurImage, const qreal radius, const bool quality, const bool alphaOnly, const int transposed = 0);
|
||||
|
||||
FRAMELESSHELPER_EXPORT bool disableExtraProcessingForBlur();
|
||||
FRAMELESSHELPER_EXPORT bool forceEnableTraditionalBlur();
|
||||
FRAMELESSHELPER_EXPORT bool forceDisableWallpaperBlur();
|
||||
FRAMELESSHELPER_EXPORT bool shouldUseNativeTitleBar();
|
||||
|
||||
FRAMELESSHELPER_EXPORT bool isWindowFixedSize(const QWindow *window);
|
||||
|
||||
FRAMELESSHELPER_EXPORT bool isMouseInSpecificObjects(const QPointF &mousePos, const QObjectList &objects, const qreal dpr = 1.0);
|
||||
|
||||
FRAMELESSHELPER_EXPORT QColor getNativeWindowFrameColor(const bool isActive = true);
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
// Windows specific
|
||||
FRAMELESSHELPER_EXPORT bool isWin7OrGreater();
|
||||
|
@ -92,22 +62,16 @@ FRAMELESSHELPER_EXPORT bool isWin10OrGreater();
|
|||
FRAMELESSHELPER_EXPORT bool isWin10OrGreater(const int subVer);
|
||||
|
||||
FRAMELESSHELPER_EXPORT bool isDwmBlurAvailable();
|
||||
FRAMELESSHELPER_EXPORT bool isOfficialMSWin10AcrylicBlurAvailable();
|
||||
|
||||
FRAMELESSHELPER_EXPORT bool isColorizationEnabled();
|
||||
FRAMELESSHELPER_EXPORT QColor getColorizationColor();
|
||||
|
||||
FRAMELESSHELPER_EXPORT bool isHighContrastModeEnabled();
|
||||
FRAMELESSHELPER_EXPORT bool isDarkFrameEnabled(const QWindow *window);
|
||||
FRAMELESSHELPER_EXPORT bool isTransparencyEffectEnabled();
|
||||
|
||||
FRAMELESSHELPER_EXPORT void triggerFrameChange(const QWindow *window);
|
||||
FRAMELESSHELPER_EXPORT void updateFrameMargins(const QWindow *window, const bool reset);
|
||||
FRAMELESSHELPER_EXPORT void updateQtFrameMargins(QWindow *window, const bool enable);
|
||||
|
||||
FRAMELESSHELPER_EXPORT quint32 getWindowDpi(const QWindow *window);
|
||||
FRAMELESSHELPER_EXPORT QMargins getWindowNativeFrameMargins(const QWindow *window);
|
||||
FRAMELESSHELPER_EXPORT QColor getNativeWindowFrameColor(const bool isActive = true);
|
||||
|
||||
FRAMELESSHELPER_EXPORT void displaySystemMenu(const QWindow *window, const QPoint &pos = {});
|
||||
#endif
|
||||
|
|
|
@ -36,11 +36,7 @@
|
|||
#include <QtCore/qt_windows.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <dwmapi.h>
|
||||
#include <shobjidl_core.h>
|
||||
#include <wininet.h>
|
||||
#include <shlobj_core.h>
|
||||
#include <QtGui/qpa/qplatformwindow.h>
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
#include <QtGui/qpa/qplatformnativeinterface.h>
|
||||
|
@ -52,9 +48,6 @@
|
|||
#else
|
||||
#include <QtCore/qsysinfo.h>
|
||||
#endif
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
#include <QtCore/qscopeguard.h>
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE(QMargins)
|
||||
|
||||
|
@ -68,61 +61,8 @@ Q_DECLARE_METATYPE(QMargins)
|
|||
#define SM_CXPADDEDBORDER 92
|
||||
#endif
|
||||
|
||||
enum : WORD
|
||||
{
|
||||
DwmwaUseImmersiveDarkMode = 20,
|
||||
DwmwaUseImmersiveDarkModeBefore20h1 = 19
|
||||
};
|
||||
|
||||
using WINDOWCOMPOSITIONATTRIB = enum _WINDOWCOMPOSITIONATTRIB
|
||||
{
|
||||
WCA_ACCENT_POLICY = 19
|
||||
};
|
||||
|
||||
using WINDOWCOMPOSITIONATTRIBDATA = struct _WINDOWCOMPOSITIONATTRIBDATA
|
||||
{
|
||||
WINDOWCOMPOSITIONATTRIB Attrib;
|
||||
PVOID pvData;
|
||||
SIZE_T cbData;
|
||||
};
|
||||
|
||||
using ACCENT_STATE = enum _ACCENT_STATE
|
||||
{
|
||||
ACCENT_DISABLED = 0,
|
||||
ACCENT_ENABLE_GRADIENT = 1,
|
||||
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
||||
ACCENT_ENABLE_BLURBEHIND = 3,
|
||||
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803
|
||||
ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809
|
||||
ACCENT_INVALID_STATE = 6
|
||||
};
|
||||
|
||||
using ACCENT_POLICY = struct _ACCENT_POLICY
|
||||
{
|
||||
ACCENT_STATE AccentState;
|
||||
DWORD AccentFlags;
|
||||
COLORREF GradientColor;
|
||||
DWORD AnimationId;
|
||||
};
|
||||
|
||||
using IMMERSIVE_HC_CACHE_MODE = enum _IMMERSIVE_HC_CACHE_MODE
|
||||
{
|
||||
IHCM_USE_CACHED_VALUE,
|
||||
IHCM_REFRESH
|
||||
};
|
||||
|
||||
using PREFERRED_APP_MODE = enum _PREFERRED_APP_MODE
|
||||
{
|
||||
Default,
|
||||
AllowDark,
|
||||
ForceDark,
|
||||
ForceLight,
|
||||
Max
|
||||
};
|
||||
|
||||
static const QString g_dwmRegistryKey = QStringLiteral(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)");
|
||||
static const QString g_personalizeRegistryKey = QStringLiteral(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)");
|
||||
static const QString g_desktopRegistryKey = QStringLiteral(R"(HKEY_CURRENT_USER\Control Panel\Desktop)");
|
||||
|
||||
// The standard values of border width, border height and title bar height when DPI is 96.
|
||||
static const int g_defaultBorderWidth = 8, g_defaultBorderHeight = 8, g_defaultTitleBarHeight = 31;
|
||||
|
@ -139,16 +79,8 @@ using PROCESS_DPI_AWARENESS = enum _PROCESS_DPI_AWARENESS
|
|||
PROCESS_PER_MONITOR_DPI_AWARE = 2
|
||||
};
|
||||
|
||||
using SetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, WINDOWCOMPOSITIONATTRIBDATA *);
|
||||
using ShouldAppsUseDarkModePtr = BOOL(WINAPI *)();
|
||||
using AllowDarkModeForWindowPtr = BOOL(WINAPI *)(HWND, BOOL);
|
||||
using AllowDarkModeForAppPtr = BOOL(WINAPI *)(BOOL);
|
||||
using IsDarkModeAllowedForWindowPtr = BOOL(WINAPI *)(HWND);
|
||||
using GetIsImmersiveColorUsingHighContrastPtr = BOOL(WINAPI *)(IMMERSIVE_HC_CACHE_MODE);
|
||||
using RefreshImmersiveColorPolicyStatePtr = VOID(WINAPI *)();
|
||||
using ShouldSystemUseDarkModePtr = BOOL(WINAPI *)();
|
||||
using SetPreferredAppModePtr = PREFERRED_APP_MODE(WINAPI *)(PREFERRED_APP_MODE);
|
||||
using IsDarkModeAllowedForAppPtr = BOOL(WINAPI *)();
|
||||
|
||||
using GetDpiForMonitorPtr = HRESULT(WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *);
|
||||
using GetProcessDpiAwarenessPtr = HRESULT(WINAPI *)(HANDLE, PROCESS_DPI_AWARENESS *);
|
||||
|
@ -160,18 +92,8 @@ using AdjustWindowRectExForDpiPtr = BOOL(WINAPI *)(LPRECT, DWORD, BOOL, DWORD, U
|
|||
|
||||
using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
|
||||
{
|
||||
_FLH_UTILITIES_WIN32_DATA() { load(); }
|
||||
|
||||
SetWindowCompositionAttributePtr SetWindowCompositionAttributePFN = nullptr;
|
||||
ShouldAppsUseDarkModePtr ShouldAppsUseDarkModePFN = nullptr;
|
||||
AllowDarkModeForWindowPtr AllowDarkModeForWindowPFN = nullptr;
|
||||
AllowDarkModeForAppPtr AllowDarkModeForAppPFN = nullptr;
|
||||
IsDarkModeAllowedForWindowPtr IsDarkModeAllowedForWindowPFN = nullptr;
|
||||
GetIsImmersiveColorUsingHighContrastPtr GetIsImmersiveColorUsingHighContrastPFN = nullptr;
|
||||
RefreshImmersiveColorPolicyStatePtr RefreshImmersiveColorPolicyStatePFN = nullptr;
|
||||
ShouldSystemUseDarkModePtr ShouldSystemUseDarkModePFN = nullptr;
|
||||
SetPreferredAppModePtr SetPreferredAppModePFN = nullptr;
|
||||
IsDarkModeAllowedForAppPtr IsDarkModeAllowedForAppPFN = nullptr;
|
||||
|
||||
GetDpiForMonitorPtr GetDpiForMonitorPFN = nullptr;
|
||||
GetProcessDpiAwarenessPtr GetProcessDpiAwarenessPFN = nullptr;
|
||||
|
@ -181,10 +103,14 @@ using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
|
|||
GetSystemMetricsForDpiPtr GetSystemMetricsForDpiPFN = nullptr;
|
||||
AdjustWindowRectExForDpiPtr AdjustWindowRectExForDpiPFN = nullptr;
|
||||
|
||||
_FLH_UTILITIES_WIN32_DATA()
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
QLibrary User32Dll(QStringLiteral("User32"));
|
||||
SetWindowCompositionAttributePFN = reinterpret_cast<SetWindowCompositionAttributePtr>(User32Dll.resolve("SetWindowCompositionAttribute"));
|
||||
GetDpiForWindowPFN = reinterpret_cast<GetDpiForWindowPtr>(User32Dll.resolve("GetDpiForWindow"));
|
||||
GetDpiForSystemPFN = reinterpret_cast<GetDpiForSystemPtr>(User32Dll.resolve("GetDpiForSystem"));
|
||||
GetSystemMetricsForDpiPFN = reinterpret_cast<GetSystemMetricsForDpiPtr>(User32Dll.resolve("GetSystemMetricsForDpi"));
|
||||
|
@ -193,14 +119,7 @@ using Win32Data = struct _FLH_UTILITIES_WIN32_DATA
|
|||
|
||||
QLibrary UxThemeDll(QStringLiteral("UxTheme"));
|
||||
ShouldAppsUseDarkModePFN = reinterpret_cast<ShouldAppsUseDarkModePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(132)));
|
||||
AllowDarkModeForWindowPFN = reinterpret_cast<AllowDarkModeForWindowPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(133)));
|
||||
AllowDarkModeForAppPFN = reinterpret_cast<AllowDarkModeForAppPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(135)));
|
||||
RefreshImmersiveColorPolicyStatePFN = reinterpret_cast<RefreshImmersiveColorPolicyStatePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(104)));
|
||||
IsDarkModeAllowedForWindowPFN = reinterpret_cast<IsDarkModeAllowedForWindowPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(137)));
|
||||
GetIsImmersiveColorUsingHighContrastPFN = reinterpret_cast<GetIsImmersiveColorUsingHighContrastPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(106)));
|
||||
ShouldSystemUseDarkModePFN = reinterpret_cast<ShouldSystemUseDarkModePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(138)));
|
||||
SetPreferredAppModePFN = reinterpret_cast<SetPreferredAppModePtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(135)));
|
||||
IsDarkModeAllowedForAppPFN = reinterpret_cast<IsDarkModeAllowedForAppPtr>(UxThemeDll.resolve(MAKEINTRESOURCEA(139)));
|
||||
|
||||
QLibrary SHCoreDll(QStringLiteral("SHCore"));
|
||||
GetDpiForMonitorPFN = reinterpret_cast<GetDpiForMonitorPtr>(SHCoreDll.resolve("GetDpiForMonitor"));
|
||||
|
@ -294,72 +213,6 @@ int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric,
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool Utilities::setBlurEffectEnabled(const QWindow *window, const bool enabled, const QColor &gradientColor)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(window->winId());
|
||||
Q_ASSERT(hwnd);
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
bool result = false;
|
||||
// We prefer DwmEnableBlurBehindWindow on Windows 7.
|
||||
if (isWin8OrGreater() && win32Data()->SetWindowCompositionAttributePFN) {
|
||||
ACCENT_POLICY accentPolicy;
|
||||
SecureZeroMemory(&accentPolicy, sizeof(accentPolicy));
|
||||
WINDOWCOMPOSITIONATTRIBDATA wcaData;
|
||||
SecureZeroMemory(&wcaData, sizeof(wcaData));
|
||||
wcaData.Attrib = WCA_ACCENT_POLICY;
|
||||
wcaData.pvData = &accentPolicy;
|
||||
wcaData.cbData = sizeof(accentPolicy);
|
||||
if (enabled) {
|
||||
// The gradient color must be set otherwise it'll look like a classic blur.
|
||||
// Use semi-transparent gradient color to get better appearance.
|
||||
if (gradientColor.isValid()) {
|
||||
accentPolicy.GradientColor = qRgba(gradientColor.blue(), gradientColor.green(), gradientColor.red(), gradientColor.alpha());
|
||||
} else {
|
||||
const QColor colorizationColor = getColorizationColor();
|
||||
accentPolicy.GradientColor =
|
||||
RGB(qRound(colorizationColor.red() * (colorizationColor.alpha() / 255.0) + 255 - colorizationColor.alpha()),
|
||||
qRound(colorizationColor.green() * (colorizationColor.alpha() / 255.0) + 255 - colorizationColor.alpha()),
|
||||
qRound(colorizationColor.blue() * (colorizationColor.alpha() / 255.0) + 255 - colorizationColor.alpha()));
|
||||
}
|
||||
if (isOfficialMSWin10AcrylicBlurAvailable()) {
|
||||
accentPolicy.AccentState = ACCENT_ENABLE_ACRYLICBLURBEHIND;
|
||||
if (!gradientColor.isValid()) {
|
||||
accentPolicy.GradientColor = 0x01FFFFFF;
|
||||
}
|
||||
} else {
|
||||
accentPolicy.AccentState = ACCENT_ENABLE_BLURBEHIND;
|
||||
}
|
||||
} else {
|
||||
accentPolicy.AccentState = ACCENT_DISABLED;
|
||||
}
|
||||
result = (win32Data()->SetWindowCompositionAttributePFN(hwnd, &wcaData) != FALSE);
|
||||
if (!result) {
|
||||
qWarning() << "SetWindowCompositionAttribute failed.";
|
||||
}
|
||||
} else {
|
||||
DWM_BLURBEHIND dwmBB;
|
||||
SecureZeroMemory(&dwmBB, sizeof(dwmBB));
|
||||
dwmBB.dwFlags = DWM_BB_ENABLE;
|
||||
dwmBB.fEnable = enabled ? TRUE : FALSE;
|
||||
result = SUCCEEDED(DwmEnableBlurBehindWindow(hwnd, &dwmBB));
|
||||
if (!result) {
|
||||
qWarning() << "DwmEnableBlurBehindWindow failed.";
|
||||
}
|
||||
}
|
||||
if (result) {
|
||||
const auto win = const_cast<QWindow *>(window);
|
||||
win->setProperty(_flh_global::_flh_acrylic_blurEnabled_flag, enabled);
|
||||
win->setProperty(_flh_global::_flh_acrylic_gradientColor_flag, gradientColor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Utilities::isColorizationEnabled()
|
||||
{
|
||||
if (!isWin10OrGreater()) {
|
||||
|
@ -411,50 +264,6 @@ bool Utilities::isDarkThemeEnabled()
|
|||
return (ok && !lightThemeEnabled);
|
||||
}
|
||||
|
||||
bool Utilities::isHighContrastModeEnabled()
|
||||
{
|
||||
HIGHCONTRASTW hc;
|
||||
SecureZeroMemory(&hc, sizeof(hc));
|
||||
hc.cbSize = sizeof(hc);
|
||||
if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, 0, &hc, 0) == FALSE) {
|
||||
qWarning() << "SystemParametersInfoW failed.";
|
||||
return false;
|
||||
}
|
||||
return hc.dwFlags & HCF_HIGHCONTRASTON;
|
||||
}
|
||||
|
||||
bool Utilities::isDarkFrameEnabled(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
if (!isWin10OrGreater(17763)) {
|
||||
return false;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(window->winId());
|
||||
Q_ASSERT(hwnd);
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
BOOL result = FALSE;
|
||||
const bool ok = SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkMode, &result, sizeof(result)))
|
||||
|| SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkModeBefore20h1, &result, sizeof(result)));
|
||||
return (ok && result);
|
||||
}
|
||||
|
||||
bool Utilities::isTransparencyEffectEnabled()
|
||||
{
|
||||
if (!isWin10OrGreater()) {
|
||||
return false;
|
||||
}
|
||||
// TODO: Is there an official Win32 API to do this?
|
||||
bool ok = false;
|
||||
const QSettings registry(g_personalizeRegistryKey, QSettings::NativeFormat);
|
||||
const bool transparencyEnabled = registry.value(QStringLiteral("EnableTransparency"), 0).toULongLong(&ok) != 0;
|
||||
return (ok && transparencyEnabled);
|
||||
}
|
||||
|
||||
void Utilities::triggerFrameChange(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
|
@ -488,243 +297,6 @@ void Utilities::updateFrameMargins(const QWindow *window, const bool reset)
|
|||
}
|
||||
}
|
||||
|
||||
QImage Utilities::getDesktopWallpaperImage(const int screen)
|
||||
{
|
||||
if (isWin8OrGreater()) {
|
||||
if (SUCCEEDED(CoInitialize(nullptr))) {
|
||||
IDesktopWallpaper* pDesktopWallpaper = nullptr;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
const auto cleanup = qScopeGuard([pDesktopWallpaper](){
|
||||
if (pDesktopWallpaper) {
|
||||
pDesktopWallpaper->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
});
|
||||
#endif
|
||||
// TODO: Why CLSCTX_INPROC_SERVER failed?
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_DesktopWallpaper, nullptr, CLSCTX_LOCAL_SERVER, IID_IDesktopWallpaper, reinterpret_cast<void **>(&pDesktopWallpaper))) && pDesktopWallpaper) {
|
||||
UINT monitorCount = 0;
|
||||
if (SUCCEEDED(pDesktopWallpaper->GetMonitorDevicePathCount(&monitorCount))) {
|
||||
if (screen > int(monitorCount - 1)) {
|
||||
qWarning() << "Screen number above total screen count.";
|
||||
return {};
|
||||
}
|
||||
const UINT monitorIndex = qMax(screen, 0);
|
||||
LPWSTR monitorId = nullptr;
|
||||
if (SUCCEEDED(pDesktopWallpaper->GetMonitorDevicePathAt(monitorIndex, &monitorId)) && monitorId) {
|
||||
LPWSTR wallpaperPath = nullptr;
|
||||
if (SUCCEEDED(pDesktopWallpaper->GetWallpaper(monitorId, &wallpaperPath)) && wallpaperPath) {
|
||||
CoTaskMemFree(monitorId);
|
||||
const QString _path = QString::fromWCharArray(wallpaperPath);
|
||||
CoTaskMemFree(wallpaperPath);
|
||||
return QImage(_path);
|
||||
} else {
|
||||
CoTaskMemFree(monitorId);
|
||||
qWarning() << "IDesktopWallpaper::GetWallpaper() failed.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "IDesktopWallpaper::GetMonitorDevicePathAt() failed";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "IDesktopWallpaper::GetMonitorDevicePathCount() failed";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to create COM instance - DesktopWallpaper.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to initialize COM.";
|
||||
}
|
||||
qDebug() << "The IDesktopWallpaper interface failed. Trying the IActiveDesktop interface instead.";
|
||||
}
|
||||
if (SUCCEEDED(CoInitialize(nullptr))) {
|
||||
IActiveDesktop *pActiveDesktop = nullptr;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
const auto cleanup = qScopeGuard([pActiveDesktop](){
|
||||
if (pActiveDesktop) {
|
||||
pActiveDesktop->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
});
|
||||
#endif
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_ActiveDesktop, nullptr, CLSCTX_INPROC_SERVER, IID_IActiveDesktop, reinterpret_cast<void **>(&pActiveDesktop))) && pActiveDesktop) {
|
||||
const auto wallpaperPath = new WCHAR[MAX_PATH];
|
||||
// TODO: AD_GETWP_BMP, AD_GETWP_IMAGE, AD_GETWP_LAST_APPLIED. What's the difference?
|
||||
if (SUCCEEDED(pActiveDesktop->GetWallpaper(wallpaperPath, MAX_PATH, AD_GETWP_LAST_APPLIED))) {
|
||||
const QString _path = QString::fromWCharArray(wallpaperPath);
|
||||
delete [] wallpaperPath;
|
||||
return QImage(_path);
|
||||
} else {
|
||||
qWarning() << "IActiveDesktop::GetWallpaper() failed.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to create COM instance - ActiveDesktop.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to initialize COM.";
|
||||
}
|
||||
qDebug() << "Shell API failed. Using SystemParametersInfoW instead.";
|
||||
const auto wallpaperPath = new WCHAR[MAX_PATH];
|
||||
if (SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaperPath, 0) != FALSE) {
|
||||
const QString _path = QString::fromWCharArray(wallpaperPath);
|
||||
delete [] wallpaperPath;
|
||||
return QImage(_path);
|
||||
}
|
||||
qWarning() << "SystemParametersInfoW failed. Reading from the registry instead.";
|
||||
const QSettings settings(g_desktopRegistryKey, QSettings::NativeFormat);
|
||||
const QString path = settings.value(QStringLiteral("WallPaper")).toString();
|
||||
if (QFileInfo::exists(path)) {
|
||||
return QImage(path);
|
||||
}
|
||||
qWarning() << "Failed to read the registry.";
|
||||
return {};
|
||||
}
|
||||
|
||||
QColor Utilities::getDesktopBackgroundColor(const int screen)
|
||||
{
|
||||
Q_UNUSED(screen);
|
||||
if (isWin8OrGreater()) {
|
||||
if (SUCCEEDED(CoInitialize(nullptr))) {
|
||||
IDesktopWallpaper *pDesktopWallpaper = nullptr;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
const auto cleanup = qScopeGuard([pDesktopWallpaper]() {
|
||||
if (pDesktopWallpaper) {
|
||||
pDesktopWallpaper->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
});
|
||||
#endif
|
||||
// TODO: Why CLSCTX_INPROC_SERVER failed?
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_DesktopWallpaper, nullptr, CLSCTX_LOCAL_SERVER, IID_IDesktopWallpaper, reinterpret_cast<void **>(&pDesktopWallpaper))) && pDesktopWallpaper) {
|
||||
COLORREF color = 0;
|
||||
if (SUCCEEDED(pDesktopWallpaper->GetBackgroundColor(&color))) {
|
||||
return QColor::fromRgba(color);
|
||||
} else {
|
||||
qWarning() << "IDesktopWallpaper::GetBackgroundColor() failed.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to create COM instance - DesktopWallpaper.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to initialize COM.";
|
||||
}
|
||||
qDebug() << "The IDesktopWallpaper interface failed.";
|
||||
}
|
||||
// TODO: Is there any other way to get the background color? Traditional Win32 API? Registry?
|
||||
// Is there a Shell API for Win7?
|
||||
return Qt::black;
|
||||
}
|
||||
|
||||
Utilities::DesktopWallpaperAspectStyle Utilities::getDesktopWallpaperAspectStyle(const int screen)
|
||||
{
|
||||
Q_UNUSED(screen);
|
||||
if (isWin8OrGreater()) {
|
||||
if (SUCCEEDED(CoInitialize(nullptr))) {
|
||||
IDesktopWallpaper *pDesktopWallpaper = nullptr;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
const auto cleanup = qScopeGuard([pDesktopWallpaper](){
|
||||
if (pDesktopWallpaper) {
|
||||
pDesktopWallpaper->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
});
|
||||
#endif
|
||||
// TODO: Why CLSCTX_INPROC_SERVER failed?
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_DesktopWallpaper, nullptr, CLSCTX_LOCAL_SERVER, IID_IDesktopWallpaper, reinterpret_cast<void **>(&pDesktopWallpaper))) && pDesktopWallpaper) {
|
||||
DESKTOP_WALLPAPER_POSITION position = DWPOS_FILL;
|
||||
if (SUCCEEDED(pDesktopWallpaper->GetPosition(&position))) {
|
||||
switch (position) {
|
||||
case DWPOS_CENTER:
|
||||
return DesktopWallpaperAspectStyle::Central;
|
||||
case DWPOS_TILE:
|
||||
return DesktopWallpaperAspectStyle::Tiled;
|
||||
case DWPOS_STRETCH:
|
||||
return DesktopWallpaperAspectStyle::IgnoreRatioFit;
|
||||
case DWPOS_FIT:
|
||||
return DesktopWallpaperAspectStyle::KeepRatioFit;
|
||||
case DWPOS_FILL:
|
||||
return DesktopWallpaperAspectStyle::KeepRatioByExpanding;
|
||||
case DWPOS_SPAN:
|
||||
return DesktopWallpaperAspectStyle::Span;
|
||||
}
|
||||
} else {
|
||||
qWarning() << "IDesktopWallpaper::GetPosition() failed.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to create COM instance - DesktopWallpaper.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to initialize COM.";
|
||||
}
|
||||
qDebug() << "The IDesktopWallpaper interface failed. Trying the IActiveDesktop interface instead.";
|
||||
}
|
||||
if (SUCCEEDED(CoInitialize(nullptr))) {
|
||||
IActiveDesktop *pActiveDesktop = nullptr;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
const auto cleanup = qScopeGuard([pActiveDesktop](){
|
||||
if (pActiveDesktop) {
|
||||
pActiveDesktop->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
});
|
||||
#endif
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_ActiveDesktop, nullptr, CLSCTX_INPROC_SERVER, IID_IActiveDesktop, reinterpret_cast<void **>(&pActiveDesktop))) && pActiveDesktop) {
|
||||
WALLPAPEROPT opt;
|
||||
SecureZeroMemory(&opt, sizeof(opt));
|
||||
opt.dwSize = sizeof(opt);
|
||||
if (SUCCEEDED(pActiveDesktop->GetWallpaperOptions(&opt, 0))) {
|
||||
switch (opt.dwStyle) {
|
||||
case WPSTYLE_CENTER:
|
||||
return DesktopWallpaperAspectStyle::Central;
|
||||
case WPSTYLE_TILE:
|
||||
return DesktopWallpaperAspectStyle::Tiled;
|
||||
case WPSTYLE_STRETCH:
|
||||
return DesktopWallpaperAspectStyle::IgnoreRatioFit;
|
||||
case WPSTYLE_KEEPASPECT:
|
||||
return DesktopWallpaperAspectStyle::KeepRatioFit;
|
||||
case WPSTYLE_CROPTOFIT:
|
||||
return DesktopWallpaperAspectStyle::KeepRatioByExpanding;
|
||||
case WPSTYLE_SPAN:
|
||||
return DesktopWallpaperAspectStyle::Span;
|
||||
}
|
||||
} else {
|
||||
qWarning() << "IActiveDesktop::GetWallpaperOptions() failed.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to create COM instance - ActiveDesktop.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Failed to initialize COM.";
|
||||
}
|
||||
qDebug() << "Shell API failed. Reading from the registry instead.";
|
||||
const QSettings settings(g_desktopRegistryKey, QSettings::NativeFormat);
|
||||
bool ok = false;
|
||||
const DWORD style = settings.value(QStringLiteral("WallpaperStyle"), 0).toULongLong(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "Failed to read the registry.";
|
||||
return DesktopWallpaperAspectStyle::KeepRatioByExpanding; // Fill
|
||||
}
|
||||
switch (style) {
|
||||
case 0: {
|
||||
bool ok = false;
|
||||
if ((settings.value(QStringLiteral("TileWallpaper"), 0).toULongLong(&ok) != 0) && ok) {
|
||||
return DesktopWallpaperAspectStyle::Tiled;
|
||||
} else {
|
||||
return DesktopWallpaperAspectStyle::Central;
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
return DesktopWallpaperAspectStyle::IgnoreRatioFit;
|
||||
case 6:
|
||||
return DesktopWallpaperAspectStyle::KeepRatioFit;
|
||||
case 10:
|
||||
return DesktopWallpaperAspectStyle::KeepRatioByExpanding;
|
||||
case 22:
|
||||
return DesktopWallpaperAspectStyle::Span;
|
||||
default:
|
||||
return DesktopWallpaperAspectStyle::KeepRatioByExpanding; // Fill
|
||||
}
|
||||
}
|
||||
|
||||
quint32 Utilities::getWindowDpi(const QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
|
@ -882,58 +454,6 @@ bool Utilities::isWin10OrGreater(const int subVer)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline bool forceEnableOfficialMSWin10AcrylicBlur()
|
||||
{
|
||||
return qEnvironmentVariableIsSet(_flh_global::_flh_acrylic_forceEnableOfficialMSWin10AcrylicBlur_flag);
|
||||
}
|
||||
|
||||
static inline bool shouldUseOfficialMSWin10AcrylicBlur()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
const QOperatingSystemVersion currentVersion = QOperatingSystemVersion::current();
|
||||
if (currentVersion > QOperatingSystemVersion::Windows10) {
|
||||
return true;
|
||||
}
|
||||
return ((currentVersion.microVersion() >= 16190) && (currentVersion.microVersion() < 18362));
|
||||
#else
|
||||
// TODO
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Utilities::isOfficialMSWin10AcrylicBlurAvailable()
|
||||
{
|
||||
if (!isWin10OrGreater()) {
|
||||
return false;
|
||||
}
|
||||
if (!forceEnableTraditionalBlur() && !forceDisableWallpaperBlur() && !disableExtraProcessingForBlur()) {
|
||||
// We can't enable the official Acrylic blur in wallpaper blur mode.
|
||||
return false;
|
||||
}
|
||||
if (forceEnableOfficialMSWin10AcrylicBlur()) {
|
||||
return true;
|
||||
}
|
||||
return shouldUseOfficialMSWin10AcrylicBlur();
|
||||
}
|
||||
|
||||
static inline bool shouldUseOriginalDwmBlur()
|
||||
{
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
return Utilities::isWin10OrGreater() || (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite);
|
||||
#else
|
||||
// TODO
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Utilities::shouldUseTraditionalBlur()
|
||||
{
|
||||
if ((forceEnableTraditionalBlur() || forceDisableWallpaperBlur() || disableExtraProcessingForBlur()) && shouldUseOriginalDwmBlur()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Utilities::displaySystemMenu(const QWindow *window, const QPoint &pos)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
|
|
Loading…
Reference in New Issue