From 208e831fc55cd97da89392e710ae86dff0d2c7bf Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Fri, 16 Oct 2020 15:48:01 +0800 Subject: [PATCH] Add a full-featured win32 example. Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- examples/Win32Demo/Win32Demo.pro | 7 + examples/Win32Demo/main.cpp | 65 +++++ examples/Win32Demo/widget.cpp | 149 ++++++++++++ examples/Win32Demo/widget.h | 49 ++++ examples/Win32Demo/widget.ui | 403 +++++++++++++++++++++++++++++++ examples/examples.pro | 1 + winnativeeventfilter.cpp | 84 +++++-- winnativeeventfilter.h | 5 +- 8 files changed, 747 insertions(+), 16 deletions(-) create mode 100644 examples/Win32Demo/Win32Demo.pro create mode 100644 examples/Win32Demo/main.cpp create mode 100644 examples/Win32Demo/widget.cpp create mode 100644 examples/Win32Demo/widget.h create mode 100644 examples/Win32Demo/widget.ui diff --git a/examples/Win32Demo/Win32Demo.pro b/examples/Win32Demo/Win32Demo.pro new file mode 100644 index 0000000..c2e7031 --- /dev/null +++ b/examples/Win32Demo/Win32Demo.pro @@ -0,0 +1,7 @@ +TARGET = Win32Demo +TEMPLATE = app +QT += widgets +HEADERS += widget.h +SOURCES += widget.cpp main.cpp +FORMS += widget.ui +include($$PWD/../common.pri) diff --git a/examples/Win32Demo/main.cpp b/examples/Win32Demo/main.cpp new file mode 100644 index 0000000..adba9a6 --- /dev/null +++ b/examples/Win32Demo/main.cpp @@ -0,0 +1,65 @@ +/* + * MIT License + * + * Copyright (C) 2020 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 "widget.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); + // High DPI scaling is enabled by default from Qt 6 +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + // Windows: we are using the manifest file to get maximum compatibility + // because some APIs are not supprted on old systems such as Windows 7 + // and Windows 8. And once we have set the DPI awareness level in the + // manifest file, any attemptation to try to change it through API will + // fail. In other words, Qt won't be able to enable or disable high DPI + // scaling or change the DPI awareness level once we have set it in the + // manifest file. So the following two lines are uesless actually (However, + // they are still useful on other platforms). + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + // Don't round the scale factor. + // This will break QWidget applications because they can't render correctly. + // Qt Quick applications won't have this issue. + QGuiApplication::setHighDpiScaleFactorRoundingPolicy( + Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); +#endif +#endif + + QApplication application(argc, argv); + + QFont font = QApplication::font(); + font.setFamily(QLatin1String("Arial")); + font.setBold(true); + font.setPointSize(15); + QApplication::setFont(font); + + Widget widget; + widget.show(); + + return QApplication::exec(); +} diff --git a/examples/Win32Demo/widget.cpp b/examples/Win32Demo/widget.cpp new file mode 100644 index 0000000..2f0ce70 --- /dev/null +++ b/examples/Win32Demo/widget.cpp @@ -0,0 +1,149 @@ +/* + * MIT License + * + * Copyright (C) 2020 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 "widget.h" +#include "../../winnativeeventfilter.h" +#include "ui_widget.h" +#include + +namespace { + +const char useNativeTitleBar[] = "WNEF_USE_NATIVE_TITLE_BAR"; +const char preserveWindowFrame[] = "WNEF_FORCE_PRESERVE_WINDOW_FRAME"; + +void *getRawHandle(QWidget *widget) +{ + Q_ASSERT(widget); + return widget->isTopLevel() ? reinterpret_cast(widget->winId()) : nullptr; +} + +void updateWindow(QWidget *widget) +{ + Q_ASSERT(widget); + if (widget->isTopLevel()) { + WinNativeEventFilter::updateWindow(getRawHandle(widget), true, true); + } +} + +} // namespace + +Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) +{ + ui->setupUi(this); + + connect(ui->minimizeButton, &QPushButton::clicked, this, &Widget::showMinimized); + connect(ui->maximizeButton, &QPushButton::clicked, this, [this]() { + if (isMaximized()) { + showNormal(); + } else { + showMaximized(); + } + }); + connect(ui->closeButton, &QPushButton::clicked, this, &Widget::close); + + connect(ui->moveCenterButton, &QPushButton::clicked, this, [this]() { + WinNativeEventFilter::moveWindowToDesktopCenter(getRawHandle(this)); + }); + + connect(this, &Widget::windowTitleChanged, ui->titleLabel, &QLabel::setText); + connect(this, &Widget::windowIconChanged, ui->iconButton, &QPushButton::setIcon); + + connect(ui->customizeTitleBarCB, &QCheckBox::stateChanged, this, [this](int state) { + const bool enable = state == Qt::Checked; + WinNativeEventFilter::updateQtFrame(windowHandle(), + enable ? WinNativeEventFilter::getSystemMetric( + getRawHandle(this), + WinNativeEventFilter::SystemMetric::TitleBarHeight) + : 0); + ui->titleBarWidget->setVisible(enable); + if (enable) { + qunsetenv(useNativeTitleBar); + } else if (state == Qt::Unchecked) { + qputenv(useNativeTitleBar, "1"); + } + updateWindow(this); + }); + connect(ui->windowFrameCB, &QCheckBox::stateChanged, this, [this](int state) { + if (state == Qt::Checked) { + qunsetenv(preserveWindowFrame); + } else if (state == Qt::Unchecked) { + qputenv(preserveWindowFrame, "1"); + } + updateWindow(this); + }); + connect(ui->blurEffectCB, &QCheckBox::stateChanged, this, [this](int state) { + const bool enable = state == Qt::Checked; + QPalette palette = {}; + // Choose the gradient color you like. + palette.setColor(QPalette::Window, QColor(255, 255, 255, 235)); + setPalette(enable ? palette : QPalette()); + WinNativeEventFilter::setBlurEffectEnabled(getRawHandle(this), enable); + updateWindow(this); + }); + connect(ui->resizableCB, &QCheckBox::stateChanged, this, [this](int state) { + const auto data = WinNativeEventFilter::windowData(this); + if (data) { + data->fixedSize = state == Qt::Unchecked; + updateWindow(this); + } + }); + + QStyleOption option; + option.initFrom(this); + setWindowIcon(style()->standardIcon(QStyle::SP_ComputerIcon, &option)); + setWindowTitle(tr("Hello, World!")); + + WinNativeEventFilter::WINDOWDATA data = {}; + data.ignoreObjects << ui->minimizeButton << ui->maximizeButton << ui->closeButton; + WinNativeEventFilter::addFramelessWindow(this, &data); + + installEventFilter(this); +} + +Widget::~Widget() +{ + delete ui; +} + +bool Widget::eventFilter(QObject *object, QEvent *event) +{ + Q_ASSERT(object); + Q_ASSERT(event); + switch (event->type()) { + case QEvent::WindowStateChange: { + if (isMaximized()) { + ui->maximizeButton->setIcon(QIcon(QLatin1String(":/images/button_restore_black.svg"))); + } else if (!isFullScreen() && !isMinimized()) { + ui->maximizeButton->setIcon(QIcon(QLatin1String(":/images/button_maximize_black.svg"))); + } + ui->moveCenterButton->setEnabled(!isMaximized() && !isFullScreen()); + } break; + case QEvent::WinIdChange: + WinNativeEventFilter::addFramelessWindow(this); + break; + default: + break; + } + return QWidget::eventFilter(object, event); +} diff --git a/examples/Win32Demo/widget.h b/examples/Win32Demo/widget.h new file mode 100644 index 0000000..2fe0cd3 --- /dev/null +++ b/examples/Win32Demo/widget.h @@ -0,0 +1,49 @@ +/* + * MIT License + * + * Copyright (C) 2020 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 + +QT_BEGIN_NAMESPACE +namespace Ui { +QT_FORWARD_DECLARE_CLASS(Widget) +} +QT_END_NAMESPACE + +class Widget : public QWidget +{ + Q_OBJECT + Q_DISABLE_COPY_MOVE(Widget) + +public: + explicit Widget(QWidget *parent = nullptr); + ~Widget(); + +protected: + bool eventFilter(QObject *object, QEvent *event) override; + +private: + Ui::Widget *ui = nullptr; +}; diff --git a/examples/Win32Demo/widget.ui b/examples/Win32Demo/widget.ui new file mode 100644 index 0000000..aae53da --- /dev/null +++ b/examples/Win32Demo/widget.ui @@ -0,0 +1,403 @@ + + + Widget + + + + 0 + 0 + 1056 + 600 + + + + Widget + + + #titleBarWidget { + background-color: rgb(255, 255, 255); +} + +#iconButton, #minimizeButton, #maximizeButton, #closeButton { + background-color: transparent; + border-radius: 0px; +} + +#minimizeButton:hover, #maximizeButton:hover { + border-style: none; + background-color: #80c7c7c7; +} + +#minimizeButton:pressed, #maximizeButton:pressed { + border-style: none; + background-color: #80808080; +} + +#closeButton:hover { + border-style: none; + background-color: #e81123; +} + +#closeButton:pressed { + border-style: none; + background-color: #8c0a15; +} + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 45 + 26 + + + + + 45 + 26 + + + + + + + + :/images/button_minimize_black.svg:/images/button_minimize_black.svg + + + + 45 + 26 + + + + + + + + + 0 + 0 + + + + + 45 + 26 + + + + + 45 + 26 + + + + + + + + :/images/button_maximize_black.svg:/images/button_maximize_black.svg + + + + 45 + 26 + + + + + + + + + 0 + 0 + + + + + 45 + 26 + + + + + 45 + 26 + + + + + + + + :/images/button_close_black.svg:/images/button_close_black.svg + + + + 45 + 26 + + + + + + + + + + + + 0 + 0 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + Enable customized title bar + + + true + + + + + + + Get rid of window frame + + + true + + + + + + + Enable blur effect + + + + + + + Resizable + + + true + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Move to desktop center + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + diff --git a/examples/examples.pro b/examples/examples.pro index c458979..bd278ad 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -2,3 +2,4 @@ TEMPLATE = subdirs CONFIG -= ordered qtHaveModule(widgets): SUBDIRS += QWidget QMainWindow qtHaveModule(quick): SUBDIRS += Quick +win32: qtHaveModule(widgets): SUBDIRS += Win32Demo diff --git a/winnativeeventfilter.cpp b/winnativeeventfilter.cpp index 993e81c..f1309fb 100644 --- a/winnativeeventfilter.cpp +++ b/winnativeeventfilter.cpp @@ -660,15 +660,28 @@ const qreal m_defaultDevicePixelRatio = 1.0; bool shouldHaveWindowFrame() { -#if 0 + const bool should = qEnvironmentVariableIsSet("WNEF_PRESERVE_WINDOW_FRAME"); + const bool force = qEnvironmentVariableIsSet("WNEF_FORCE_PRESERVE_WINDOW_FRAME"); + if (should || force) { + if (force) { + return true; + } + if (should) { + // If you preserve the window frame on Win7~8.1, + // the window will have a terrible appearance. #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) - return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10; + return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10; #else - return QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10; + return QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10; #endif -#else + } + } return false; -#endif +} + +bool shouldUseNativeTitleBar() +{ + return qEnvironmentVariableIsSet("WNEF_USE_NATIVE_TITLE_BAR"); } BOOL IsDwmCompositionEnabled() @@ -959,17 +972,23 @@ void UpdateFrameMarginsForWindow(const HWND handle) const auto GetTopBorderHeight = [](const HWND handle) -> int { Q_ASSERT(handle); if (WNEF_EXECUTE_WINAPI_RETURN(IsWindow, FALSE, handle)) { - if (IsMaximized(handle) || IsFullScreen(handle) || !IsDwmCompositionEnabled()) { - return 0; + if (IsDwmCompositionEnabled() && !IsMaximized(handle) && !IsFullScreen(handle)) { + return 1; } } - return 1; + return 0; }; if (GetTopBorderHeight(handle) != 0) { margins.cyTopHeight = GetFrameSizeForWindow(handle, TRUE).top; } } else { margins.cyTopHeight = 1; + //margins.cyTopHeight = GetFrameSizeForWindow(handle, TRUE).top; + } + if (shouldUseNativeTitleBar()) { + // If we are going to use the native title bar, + // we should use the original window frame as well. + margins = {0, 0, 0, 0}; } WNEF_EXECUTE_WINAPI(DwmExtendFrameIntoClientArea, handle, &margins) } @@ -1353,7 +1372,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, // Bring our frame shadow back through DWM, don't draw it manually. UpdateFrameMarginsForWindow(msg->hwnd); // Blur effect. - setAcrylicEffectEnabled(msg->hwnd, data->enableBlurBehindWindow); + setBlurEffectEnabled(msg->hwnd, data->enableBlurBehindWindow); } switch (msg->message) { case WM_NCCALCSIZE: { @@ -1427,6 +1446,10 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, // preserve the four window borders. So we just remove the whole // window frame, otherwise the code will become much more complex. + if (shouldUseNativeTitleBar()) { + break; + } + const auto mode = static_cast(msg->wParam); // If the window bounds change, we're going to relayout and repaint // anyway. Returning WVR_REDRAW avoids an extra paint before that of @@ -1594,7 +1617,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, // area. case WM_NCUAHDRAWCAPTION: case WM_NCUAHDRAWFRAME: { - if (shouldHaveWindowFrame()) { + if (shouldHaveWindowFrame() || shouldUseNativeTitleBar()) { break; } else { *result = 0; @@ -1604,7 +1627,8 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, case WM_NCPAINT: { // 边框阴影处于非客户区的范围,因此如果直接阻止非客户区的绘制,会导致边框阴影丢失 - if (!IsDwmCompositionEnabled() && !shouldHaveWindowFrame()) { + if (!IsDwmCompositionEnabled() && !shouldHaveWindowFrame() + && !shouldUseNativeTitleBar()) { // Only block WM_NCPAINT when DWM composition is disabled. If // it's blocked when DWM composition is enabled, the frame // shadow won't be drawn. @@ -1615,7 +1639,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, } } case WM_NCACTIVATE: { - if (shouldHaveWindowFrame()) { + if (shouldHaveWindowFrame() || shouldUseNativeTitleBar()) { break; } else { if (IsDwmCompositionEnabled()) { @@ -1707,6 +1731,10 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, // another branch, if you are interested in it, you can give it a // try. + if (shouldUseNativeTitleBar()) { + break; + } + if (data->mouseTransparent) { // Mouse events will be passed to the parent window. *result = HTTRANSPARENT; @@ -1947,6 +1975,10 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, } case WM_SETICON: case WM_SETTEXT: { + if (shouldUseNativeTitleBar()) { + break; + } + // Disable painting while these messages are handled to prevent them // from drawing a window caption over the client area. const auto oldStyle = WNEF_EXECUTE_WINAPI_RETURN(GetWindowLongPtrW, @@ -1968,7 +2000,11 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, *result = ret; return true; } - case WM_DWMCOMPOSITIONCHANGED: + case WM_DWMCOMPOSITIONCHANGED: { + if (shouldUseNativeTitleBar()) { + break; + } + // DWM won't draw the frame shadow if the window doesn't have a // frame. So extend the window frame a bit to make sure we still // have the frame shadow. But don't worry, the extended window frame @@ -1976,6 +2012,7 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, // as what we did in WM_NCCALCSIZE. UpdateFrameMarginsForWindow(msg->hwnd); break; + } case WM_DPICHANGED: // Sent when the effective dots per inch (dpi) for a window has // changed. You won't get this message until Windows 8.1 @@ -1998,6 +2035,10 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, // https://code.qt.io/cgit/qt/qtbase.git/tree/src/plugins/platforms/windows/qwindowscontext.cpp break; case WM_CONTEXTMENU: { + if (shouldUseNativeTitleBar()) { + break; + } + // If the context menu is brought up from the keyboard // (SHIFT + F10 or the context menu key), lParam will be -1. const LPARAM lParam = (msg->lParam == -1) ? WNEF_EXECUTE_WINAPI_RETURN(GetMessagePos, 0) @@ -2011,6 +2052,10 @@ bool WinNativeEventFilter::nativeEventFilter(const QByteArray &eventType, } } case WM_MOVE: { + if (shouldUseNativeTitleBar()) { + break; + } + const QString sn = getCurrentScreenSerialNumber(msg->hwnd); if (data->currentScreen.toUpper() != sn) { data->currentScreen = sn; @@ -2222,7 +2267,7 @@ void WinNativeEventFilter::moveWindowToDesktopCenter(void *handle) void WinNativeEventFilter::updateQtFrame(QWindow *window, const int titleBarHeight) { Q_ASSERT(window); - if (titleBarHeight > 0) { + if (titleBarHeight >= 0) { // Reduce top frame to zero since we paint it ourselves. Use // device pixel to avoid rounding errors. const QMargins margins = {0, -titleBarHeight, 0, 0}; @@ -2301,7 +2346,7 @@ bool WinNativeEventFilter::displaySystemMenu(void *handle, return false; } -bool WinNativeEventFilter::setAcrylicEffectEnabled(void *handle, const bool enabled) +bool WinNativeEventFilter::setBlurEffectEnabled(void *handle, const bool enabled) { Q_ASSERT(handle); const auto hwnd = reinterpret_cast(handle); @@ -2343,3 +2388,12 @@ bool WinNativeEventFilter::setAcrylicEffectEnabled(void *handle, const bool enab } return false; } + +void WinNativeEventFilter::updateFrameMargins(void *handle) +{ + Q_ASSERT(handle); + const auto hwnd = reinterpret_cast(handle); + if (WNEF_EXECUTE_WINAPI_RETURN(IsWindow, FALSE, hwnd)) { + UpdateFrameMarginsForWindow(hwnd); + } +} diff --git a/winnativeeventfilter.h b/winnativeeventfilter.h index b3bee36..99743f7 100644 --- a/winnativeeventfilter.h +++ b/winnativeeventfilter.h @@ -141,7 +141,10 @@ public: // Enable or disable the blur effect for a specific window. // On Win10 it's the Acrylic effect. - static bool setAcrylicEffectEnabled(void *handle /* HWND */, const bool enabled = true); + static bool setBlurEffectEnabled(void *handle /* HWND */, const bool enabled = true); + + // a + static void updateFrameMargins(void *handle /* HWND */); /////////////////////////////////////////////// /// CORE FUNCTION - THE SOUL OF THIS CODE