Add a full-featured win32 example.

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2020-10-16 15:48:01 +08:00
parent c95e8fc806
commit 208e831fc5
8 changed files with 747 additions and 16 deletions

View File

@ -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)

View File

@ -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 <QApplication>
#include <QFont>
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();
}

View File

@ -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 <QStyleOption>
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<void *>(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);
}

View File

@ -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 <QWidget>
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;
};

View File

@ -0,0 +1,403 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1056</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<property name="styleSheet">
<string notr="true">#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;
}</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="titleBarWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>30</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="iconButton">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="titleLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="minimizeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../windows.qrc">
<normaloff>:/images/button_minimize_black.svg</normaloff>:/images/button_minimize_black.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="maximizeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../windows.qrc">
<normaloff>:/images/button_maximize_black.svg</normaloff>:/images/button_maximize_black.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../windows.qrc">
<normaloff>:/images/button_close_black.svg</normaloff>:/images/button_close_black.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>45</width>
<height>26</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="contentsWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="controlPanelWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="customizeTitleBarCB">
<property name="text">
<string>Enable customized title bar</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="windowFrameCB">
<property name="text">
<string>Get rid of window frame</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="blurEffectCB">
<property name="text">
<string>Enable blur effect</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="resizableCB">
<property name="text">
<string>Resizable</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="moveCenterButton">
<property name="text">
<string>Move to desktop center</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../windows.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -2,3 +2,4 @@ TEMPLATE = subdirs
CONFIG -= ordered
qtHaveModule(widgets): SUBDIRS += QWidget QMainWindow
qtHaveModule(quick): SUBDIRS += Quick
win32: qtHaveModule(widgets): SUBDIRS += Win32Demo

View File

@ -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<BOOL>(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<HWND>(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<HWND>(handle);
if (WNEF_EXECUTE_WINAPI_RETURN(IsWindow, FALSE, hwnd)) {
UpdateFrameMarginsForWindow(hwnd);
}
}

View File

@ -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