2024-03-28 19:18:56 +08:00
|
|
|
#include "FluFrameless.h"
|
2024-08-21 16:12:35 +08:00
|
|
|
#include "FluTheme.h"
|
2024-03-28 19:18:56 +08:00
|
|
|
|
|
|
|
#include <QQuickWindow>
|
|
|
|
#include <QGuiApplication>
|
|
|
|
#include <QScreen>
|
2024-04-03 13:24:30 +08:00
|
|
|
#include <QDateTime>
|
2024-04-23 13:41:26 +08:00
|
|
|
#include "FluTools.h"
|
2024-03-28 19:18:56 +08:00
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
2024-04-30 19:38:05 +08:00
|
|
|
|
2024-08-21 17:56:23 +08:00
|
|
|
static DwmSetWindowAttributeFunc pDwmSetWindowAttribute = nullptr;
|
|
|
|
static DwmExtendFrameIntoClientAreaFunc pDwmExtendFrameIntoClientArea = nullptr;
|
|
|
|
static DwmIsCompositionEnabledFunc pDwmIsCompositionEnabled = nullptr;
|
|
|
|
static DwmEnableBlurBehindWindowFunc pDwmEnableBlurBehindWindow = nullptr;
|
|
|
|
static SetWindowCompositionAttributeFunc pSetWindowCompositionAttribute = nullptr;
|
|
|
|
|
2024-08-21 16:12:35 +08:00
|
|
|
static RTL_OSVERSIONINFOW GetRealOSVersionImpl() {
|
|
|
|
HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
|
|
|
|
using RtlGetVersionPtr = NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
|
|
|
|
auto pRtlGetVersion =
|
|
|
|
reinterpret_cast<RtlGetVersionPtr>(::GetProcAddress(hMod, "RtlGetVersion"));
|
|
|
|
RTL_OSVERSIONINFOW rovi{};
|
|
|
|
rovi.dwOSVersionInfoSize = sizeof(rovi);
|
|
|
|
pRtlGetVersion(&rovi);
|
|
|
|
return rovi;
|
|
|
|
}
|
|
|
|
|
|
|
|
RTL_OSVERSIONINFOW GetRealOSVersion() {
|
|
|
|
static const auto result = GetRealOSVersionImpl();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isWin8OrGreater() {
|
|
|
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
|
|
|
return (rovi.dwMajorVersion > 6) || (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isWin8Point1OrGreater() {
|
|
|
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
|
|
|
return (rovi.dwMajorVersion > 6) || (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isWin10OrGreater() {
|
|
|
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
|
|
|
return (rovi.dwMajorVersion > 10) || (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isWin101809OrGreater() {
|
|
|
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
|
|
|
return (rovi.dwMajorVersion > 10) ||
|
|
|
|
(rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 && rovi.dwBuildNumber >= 17763);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isWin101903OrGreater() {
|
|
|
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
|
|
|
return (rovi.dwMajorVersion > 10) ||
|
|
|
|
(rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 && rovi.dwBuildNumber >= 18362);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isWin11OrGreater() {
|
|
|
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
|
|
|
return (rovi.dwMajorVersion > 10) ||
|
|
|
|
(rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 && rovi.dwBuildNumber >= 22000);
|
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
|
2024-08-21 16:12:35 +08:00
|
|
|
static inline bool isWin1122H2OrGreater() {
|
|
|
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
|
|
|
return (rovi.dwMajorVersion > 10) ||
|
|
|
|
(rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 && rovi.dwBuildNumber >= 22621);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isWin10Only() {
|
|
|
|
return isWin10OrGreater() && !isWin11OrGreater();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isWin7Only() {
|
|
|
|
RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
|
2024-08-27 17:27:17 +08:00
|
|
|
return rovi.dwMajorVersion == 7;
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
|
|
|
|
static inline QByteArray qtNativeEventType() {
|
2024-03-28 19:18:56 +08:00
|
|
|
static const auto result = "windows_generic_MSG";
|
|
|
|
return result;
|
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
|
2024-08-21 22:50:43 +08:00
|
|
|
static inline bool initializeFunctionPointers() {
|
|
|
|
HMODULE module = LoadLibraryW(L"dwmapi.dll");
|
2024-04-11 14:51:43 +08:00
|
|
|
if (module) {
|
2024-08-21 22:50:43 +08:00
|
|
|
if (!pDwmSetWindowAttribute) {
|
|
|
|
pDwmSetWindowAttribute = reinterpret_cast<DwmSetWindowAttributeFunc>(
|
|
|
|
GetProcAddress(module, "DwmSetWindowAttribute"));
|
|
|
|
if (!pDwmSetWindowAttribute) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!pDwmExtendFrameIntoClientArea) {
|
|
|
|
pDwmExtendFrameIntoClientArea = reinterpret_cast<DwmExtendFrameIntoClientAreaFunc>(
|
|
|
|
GetProcAddress(module, "DwmExtendFrameIntoClientArea"));
|
|
|
|
if (!pDwmExtendFrameIntoClientArea) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!pDwmIsCompositionEnabled) {
|
|
|
|
pDwmIsCompositionEnabled = reinterpret_cast<DwmIsCompositionEnabledFunc>(
|
|
|
|
::GetProcAddress(module, "DwmIsCompositionEnabled"));
|
|
|
|
if (!pDwmIsCompositionEnabled) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!pDwmEnableBlurBehindWindow) {
|
2024-08-27 17:27:17 +08:00
|
|
|
pDwmEnableBlurBehindWindow = reinterpret_cast<DwmEnableBlurBehindWindowFunc>(
|
|
|
|
GetProcAddress(module, "DwmEnableBlurBehindWindow"));
|
2024-08-21 22:50:43 +08:00
|
|
|
if (!pDwmEnableBlurBehindWindow) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
2024-08-21 22:50:43 +08:00
|
|
|
if (!pSetWindowCompositionAttribute) {
|
|
|
|
HMODULE user32 = LoadLibraryW(L"user32.dll");
|
|
|
|
if (!user32) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pSetWindowCompositionAttribute = reinterpret_cast<SetWindowCompositionAttributeFunc>(
|
|
|
|
GetProcAddress(user32, "SetWindowCompositionAttribute"));
|
|
|
|
if (!pSetWindowCompositionAttribute) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool isCompositionEnabled() {
|
2024-08-27 17:27:17 +08:00
|
|
|
if (initializeFunctionPointers()) {
|
2024-08-21 22:50:43 +08:00
|
|
|
BOOL composition_enabled = false;
|
|
|
|
pDwmIsCompositionEnabled(&composition_enabled);
|
2024-03-28 19:18:56 +08:00
|
|
|
return composition_enabled;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
|
2024-06-14 17:44:31 +08:00
|
|
|
static inline void setShadow(HWND hwnd) {
|
|
|
|
const MARGINS shadow = {1, 0, 0, 0};
|
2024-08-21 22:50:43 +08:00
|
|
|
if (initializeFunctionPointers()) {
|
|
|
|
pDwmExtendFrameIntoClientArea(hwnd, &shadow);
|
2024-06-14 17:44:31 +08:00
|
|
|
}
|
2024-08-27 17:27:17 +08:00
|
|
|
if(isWin7Only()){
|
|
|
|
SetClassLong(hwnd, GCL_STYLE, GetClassLong(hwnd, GCL_STYLE) | CS_DROPSHADOW);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setWindowRoundCorners(HWND hwnd) {
|
|
|
|
const MARGINS shadow = {-15};
|
|
|
|
if (initializeFunctionPointers()) {
|
|
|
|
pDwmExtendFrameIntoClientArea(hwnd, &shadow);
|
|
|
|
}
|
|
|
|
RECT rect;
|
|
|
|
GetWindowRect(hwnd, &rect);
|
|
|
|
int width = rect.right - rect.left;
|
|
|
|
int height = rect.bottom - rect.top;
|
|
|
|
const int radius = 15;
|
|
|
|
HRGN hRgn = CreateRoundRectRgn(0, 0, width + 1, height + 1, radius, radius);
|
|
|
|
SetWindowRgn(hwnd, hRgn, TRUE);
|
|
|
|
SetClassLong(hwnd, GCL_STYLE, GetClassLong(hwnd, GCL_STYLE) | CS_DROPSHADOW);
|
|
|
|
DeleteObject(hRgn);
|
2024-06-14 17:44:31 +08:00
|
|
|
}
|
|
|
|
|
2024-08-21 16:12:35 +08:00
|
|
|
static inline bool setWindowDarkMode(HWND hwnd, const BOOL enable) {
|
2024-08-21 22:50:43 +08:00
|
|
|
if (!initializeFunctionPointers()) {
|
|
|
|
return false;
|
2024-08-21 17:56:23 +08:00
|
|
|
}
|
|
|
|
return bool(pDwmSetWindowAttribute(hwnd, 20, &enable, sizeof(BOOL)));
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool setWindowEffect(HWND hwnd, const QString &key, const bool &enable) {
|
|
|
|
static constexpr const MARGINS extendedMargins = {-1, -1, -1, -1};
|
|
|
|
if (key == QStringLiteral("mica")) {
|
2024-08-21 22:50:43 +08:00
|
|
|
if (!isWin11OrGreater() || !initializeFunctionPointers()) {
|
2024-08-21 16:12:35 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (enable) {
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
|
2024-08-21 16:12:35 +08:00
|
|
|
if (isWin1122H2OrGreater()) {
|
2024-08-21 17:16:39 +08:00
|
|
|
const DWORD backdropType = _DWMSBT_MAINWINDOW;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
2024-08-21 16:12:35 +08:00
|
|
|
} else {
|
|
|
|
const BOOL enable = TRUE;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmSetWindowAttribute(hwnd, 1029, &enable, sizeof(enable));
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (isWin1122H2OrGreater()) {
|
2024-08-21 17:16:39 +08:00
|
|
|
const DWORD backdropType = _DWMSBT_AUTO;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
2024-08-21 16:12:35 +08:00
|
|
|
} else {
|
|
|
|
const BOOL enable = FALSE;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmSetWindowAttribute(hwnd, 1029, &enable, sizeof(enable));
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOL isDark = FluTheme::getInstance()->dark();
|
|
|
|
setWindowDarkMode(hwnd, isDark);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key == QStringLiteral("mica-alt")) {
|
2024-08-21 22:50:43 +08:00
|
|
|
if (!isWin1122H2OrGreater() || !initializeFunctionPointers()) {
|
2024-08-21 16:12:35 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (enable) {
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
|
2024-08-21 17:16:39 +08:00
|
|
|
const DWORD backdropType = _DWMSBT_TABBEDWINDOW;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
2024-08-21 16:12:35 +08:00
|
|
|
} else {
|
2024-08-21 17:16:39 +08:00
|
|
|
const DWORD backdropType = _DWMSBT_AUTO;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
|
|
|
BOOL isDark = FluTheme::getInstance()->dark();
|
|
|
|
setWindowDarkMode(hwnd, isDark);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key == QStringLiteral("acrylic")) {
|
2024-08-21 22:50:43 +08:00
|
|
|
if (!isWin11OrGreater() || !initializeFunctionPointers()) {
|
2024-08-21 16:12:35 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (enable) {
|
2024-08-21 22:50:43 +08:00
|
|
|
pDwmExtendFrameIntoClientArea(hwnd, &extendedMargins);
|
2024-08-21 17:56:23 +08:00
|
|
|
DWORD system_backdrop_type = _DWMSBT_TRANSIENTWINDOW;
|
|
|
|
pDwmSetWindowAttribute(hwnd, 38, &system_backdrop_type, sizeof(DWORD));
|
2024-08-21 16:12:35 +08:00
|
|
|
} else {
|
2024-08-21 17:16:39 +08:00
|
|
|
const DWORD backdropType = _DWMSBT_AUTO;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmSetWindowAttribute(hwnd, 38, &backdropType, sizeof(backdropType));
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
|
|
|
BOOL isDark = FluTheme::getInstance()->dark();
|
|
|
|
setWindowDarkMode(hwnd, isDark);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key == QStringLiteral("dwm-blur")) {
|
2024-08-21 22:50:43 +08:00
|
|
|
if ((isWin7Only() && !isCompositionEnabled()) || !initializeFunctionPointers()) {
|
2024-08-21 16:12:35 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
BOOL isDark = FluTheme::getInstance()->dark();
|
|
|
|
setWindowDarkMode(hwnd, isDark && enable);
|
|
|
|
if (enable) {
|
|
|
|
if (isWin8OrGreater()) {
|
|
|
|
ACCENT_POLICY policy{};
|
|
|
|
policy.dwAccentState = ACCENT_ENABLE_BLURBEHIND;
|
|
|
|
policy.dwAccentFlags = ACCENT_NONE;
|
|
|
|
WINDOWCOMPOSITIONATTRIBDATA wcad{};
|
|
|
|
wcad.Attrib = WCA_ACCENT_POLICY;
|
|
|
|
wcad.pvData = &policy;
|
|
|
|
wcad.cbData = sizeof(policy);
|
2024-08-21 17:56:23 +08:00
|
|
|
pSetWindowCompositionAttribute(hwnd, &wcad);
|
2024-08-21 16:12:35 +08:00
|
|
|
} else {
|
|
|
|
DWM_BLURBEHIND bb{};
|
|
|
|
bb.fEnable = TRUE;
|
|
|
|
bb.dwFlags = DWM_BB_ENABLE;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmEnableBlurBehindWindow(hwnd, &bb);
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (isWin8OrGreater()) {
|
|
|
|
ACCENT_POLICY policy{};
|
|
|
|
policy.dwAccentState = ACCENT_DISABLED;
|
|
|
|
policy.dwAccentFlags = ACCENT_NONE;
|
|
|
|
WINDOWCOMPOSITIONATTRIBDATA wcad{};
|
|
|
|
wcad.Attrib = WCA_ACCENT_POLICY;
|
|
|
|
wcad.pvData = &policy;
|
|
|
|
wcad.cbData = sizeof(policy);
|
2024-08-21 17:56:23 +08:00
|
|
|
pSetWindowCompositionAttribute(hwnd, &wcad);
|
2024-08-21 16:12:35 +08:00
|
|
|
} else {
|
|
|
|
DWM_BLURBEHIND bb{};
|
|
|
|
bb.fEnable = FALSE;
|
|
|
|
bb.dwFlags = DWM_BB_ENABLE;
|
2024-08-21 17:56:23 +08:00
|
|
|
pDwmEnableBlurBehindWindow(hwnd, &bb);
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-03-28 19:18:56 +08:00
|
|
|
#endif
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
bool containsCursorToItem(QQuickItem *item) {
|
|
|
|
if (!item || !item->isVisible()) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-05-03 01:54:38 +08:00
|
|
|
auto point = item->window()->mapFromGlobal(QCursor::pos());
|
|
|
|
auto rect = QRectF(item->mapToItem(item->window()->contentItem(), QPointF(0, 0)), item->size());
|
|
|
|
if (rect.contains(point)) {
|
2024-04-11 14:51:43 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
FluFrameless::FluFrameless(QQuickItem *parent) : QQuickItem{parent} {
|
|
|
|
_fixSize = false;
|
|
|
|
_appbar = nullptr;
|
|
|
|
_maximizeButton = nullptr;
|
|
|
|
_minimizedButton = nullptr;
|
|
|
|
_closeButton = nullptr;
|
|
|
|
_topmost = false;
|
|
|
|
_disabled = false;
|
2024-08-21 16:12:35 +08:00
|
|
|
_effect = "normal";
|
2024-08-24 19:22:42 +08:00
|
|
|
_effective = false;
|
2024-04-23 13:41:26 +08:00
|
|
|
_isWindows11OrGreater = FluTools::getInstance()->isWindows11OrGreater();
|
2024-03-31 21:52:06 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
FluFrameless::~FluFrameless() = default;
|
|
|
|
|
|
|
|
[[maybe_unused]] void FluFrameless::onDestruction() {
|
|
|
|
QGuiApplication::instance()->removeNativeEventFilter(this);
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::componentComplete() {
|
2024-08-24 19:22:42 +08:00
|
|
|
#ifdef Q_OS_WIN
|
2024-08-24 19:27:54 +08:00
|
|
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
2024-08-21 16:12:35 +08:00
|
|
|
if (isWin11OrGreater()) {
|
|
|
|
availableEffects({"mica", "mica-alt", "acrylic", "dwm-blur", "normal"});
|
|
|
|
} else if (isWin7Only()) {
|
2024-08-24 19:22:42 +08:00
|
|
|
availableEffects({"dwm-blur", "normal"});
|
2024-08-21 16:12:35 +08:00
|
|
|
}
|
|
|
|
if (!_effect.isEmpty()) {
|
|
|
|
effective(setWindowEffect(hwnd, _effect, true));
|
|
|
|
if (effective()) {
|
|
|
|
_currentEffect = effect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
connect(this, &FluFrameless::effectChanged, this, [hwnd, this] {
|
|
|
|
if (effect() == _currentEffect) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (effective()) {
|
|
|
|
setWindowEffect(hwnd, _currentEffect, false);
|
|
|
|
}
|
|
|
|
effective(setWindowEffect(hwnd, effect(), true));
|
|
|
|
if (effective()) {
|
|
|
|
_currentEffect = effect();
|
|
|
|
} else {
|
|
|
|
_effect = "normal";
|
|
|
|
_currentEffect = "normal";
|
|
|
|
}
|
|
|
|
});
|
|
|
|
connect(FluTheme::getInstance(), &FluTheme::blurBehindWindowEnabledChanged, this, [this] {
|
|
|
|
if (FluTheme::getInstance()->blurBehindWindowEnabled()) {
|
|
|
|
effect("normal");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
connect(FluTheme::getInstance(), &FluTheme::darkChanged, this, [hwnd, this] {
|
|
|
|
if (effective() && !_currentEffect.isEmpty() && _currentEffect != "normal") {
|
|
|
|
setWindowDarkMode(hwnd, FluTheme::getInstance()->dark());
|
|
|
|
}
|
|
|
|
});
|
2024-08-24 19:22:42 +08:00
|
|
|
if (_disabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
# if (QT_VERSION == QT_VERSION_CHECK(6, 5, 3))
|
|
|
|
qWarning()
|
|
|
|
<< "Qt's own frameless bug, currently only exist in 6.5.3, please use other versions";
|
|
|
|
# endif
|
|
|
|
DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
|
|
|
|
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
|
|
|
style &= ~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
|
|
|
|
# endif
|
|
|
|
if (_fixSize) {
|
|
|
|
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION);
|
|
|
|
;
|
|
|
|
for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) {
|
|
|
|
connect(
|
|
|
|
QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] {
|
|
|
|
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
|
|
|
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
|
|
|
|
}
|
|
|
|
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
|
|
|
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
|
|
|
connect(window(), &QQuickWindow::screenChanged, this, [hwnd] {
|
|
|
|
::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
|
|
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED |
|
|
|
|
SWP_NOOWNERZORDER);
|
|
|
|
::RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
|
|
|
|
});
|
|
|
|
if (!window()->property("_hideShadow").toBool()) {
|
|
|
|
setShadow(hwnd);
|
|
|
|
}
|
2024-03-28 19:18:56 +08:00
|
|
|
#endif
|
2024-08-24 19:22:42 +08:00
|
|
|
if (_disabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int w = window()->width();
|
|
|
|
int h = window()->height();
|
|
|
|
_current = window()->winId();
|
2024-08-27 17:27:17 +08:00
|
|
|
window()->setFlags((window()->flags()) | Qt::CustomizeWindowHint |
|
|
|
|
Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint);
|
2024-08-24 19:22:42 +08:00
|
|
|
if (!_fixSize) {
|
|
|
|
window()->setFlag(Qt::WindowMaximizeButtonHint);
|
|
|
|
}
|
|
|
|
window()->installEventFilter(this);
|
|
|
|
QGuiApplication::instance()->installNativeEventFilter(this);
|
|
|
|
if (_maximizeButton) {
|
|
|
|
setHitTestVisible(_maximizeButton);
|
|
|
|
}
|
|
|
|
if (_minimizedButton) {
|
|
|
|
setHitTestVisible(_minimizedButton);
|
|
|
|
}
|
|
|
|
if (_closeButton) {
|
|
|
|
setHitTestVisible(_closeButton);
|
|
|
|
}
|
2024-05-13 18:28:28 +08:00
|
|
|
auto appBarHeight = _appbar->height();
|
|
|
|
h = qRound(h + appBarHeight);
|
2024-04-23 13:41:26 +08:00
|
|
|
if (_fixSize) {
|
|
|
|
window()->setMaximumSize(QSize(w, h));
|
|
|
|
window()->setMinimumSize(QSize(w, h));
|
2024-05-17 21:19:10 +08:00
|
|
|
} else {
|
|
|
|
window()->setMinimumHeight(window()->minimumHeight() + appBarHeight);
|
|
|
|
window()->setMaximumHeight(window()->maximumHeight() + appBarHeight);
|
2024-04-17 15:11:14 +08:00
|
|
|
}
|
2024-04-23 13:41:26 +08:00
|
|
|
window()->resize(QSize(w, h));
|
2024-08-27 17:27:17 +08:00
|
|
|
connect(this, &FluFrameless::topmostChanged, this, [this] { _setWindowTopmost(topmost()); });
|
2024-03-28 19:18:56 +08:00
|
|
|
_setWindowTopmost(topmost());
|
2024-08-27 17:27:17 +08:00
|
|
|
_setMaximizeHovered(false);
|
|
|
|
_setMaximizePressed(false);
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
|
2024-08-27 17:27:17 +08:00
|
|
|
[[maybe_unused]] bool FluFrameless::nativeEventFilter(const QByteArray &eventType, void *message,
|
|
|
|
QT_NATIVE_EVENT_RESULT_TYPE *result) {
|
2024-03-28 19:18:56 +08:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
if ((eventType != qtNativeEventType()) || !message) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto msg = static_cast<const MSG *>(message);
|
2024-04-11 14:51:43 +08:00
|
|
|
auto hwnd = msg->hwnd;
|
|
|
|
if (!hwnd) {
|
2024-03-28 19:18:56 +08:00
|
|
|
return false;
|
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
const quint64 wid = reinterpret_cast<qint64>(hwnd);
|
|
|
|
if (wid != _current) {
|
2024-03-28 19:18:56 +08:00
|
|
|
return false;
|
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
const auto uMsg = msg->message;
|
|
|
|
const auto wParam = msg->wParam;
|
|
|
|
const auto lParam = msg->lParam;
|
|
|
|
if (uMsg == WM_WINDOWPOSCHANGING) {
|
|
|
|
auto *wp = reinterpret_cast<WINDOWPOS *>(lParam);
|
|
|
|
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0) {
|
2024-03-28 19:18:56 +08:00
|
|
|
wp->flags |= SWP_NOCOPYBITS;
|
2024-08-27 17:27:17 +08:00
|
|
|
*result = static_cast<QT_NATIVE_EVENT_RESULT_TYPE>(
|
|
|
|
::DefWindowProcW(hwnd, uMsg, wParam, lParam));
|
2024-03-28 19:18:56 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2024-05-03 16:56:40 +08:00
|
|
|
} else if (uMsg == WM_NCCALCSIZE && wParam == TRUE) {
|
2024-06-21 12:23:23 +08:00
|
|
|
bool isMaximum = ::IsZoomed(hwnd);
|
|
|
|
if (isMaximum) {
|
2024-08-27 17:27:17 +08:00
|
|
|
window()->setProperty("__margins", 7);
|
|
|
|
} else {
|
|
|
|
window()->setProperty("__margins", 0);
|
2024-06-21 12:23:23 +08:00
|
|
|
}
|
2024-03-31 21:52:06 +08:00
|
|
|
_setMaximizeHovered(false);
|
2024-03-28 19:18:56 +08:00
|
|
|
*result = WVR_REDRAW;
|
|
|
|
return true;
|
2024-04-11 14:51:43 +08:00
|
|
|
} else if (uMsg == WM_NCHITTEST) {
|
2024-04-23 13:41:26 +08:00
|
|
|
if (_isWindows11OrGreater) {
|
|
|
|
if (_hitMaximizeButton()) {
|
|
|
|
if (*result == HTNOWHERE) {
|
|
|
|
*result = HTZOOM;
|
|
|
|
}
|
|
|
|
_setMaximizeHovered(true);
|
|
|
|
return true;
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*result = 0;
|
|
|
|
POINT nativeGlobalPos{GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
|
|
|
POINT nativeLocalPos = nativeGlobalPos;
|
|
|
|
::ScreenToClient(hwnd, &nativeLocalPos);
|
|
|
|
RECT clientRect{0, 0, 0, 0};
|
|
|
|
::GetClientRect(hwnd, &clientRect);
|
2024-04-11 14:51:43 +08:00
|
|
|
auto clientWidth = clientRect.right - clientRect.left;
|
|
|
|
auto clientHeight = clientRect.bottom - clientRect.top;
|
2024-03-28 19:18:56 +08:00
|
|
|
bool left = nativeLocalPos.x < _margins;
|
|
|
|
bool right = nativeLocalPos.x > clientWidth - _margins;
|
|
|
|
bool top = nativeLocalPos.y < _margins;
|
|
|
|
bool bottom = nativeLocalPos.y > clientHeight - _margins;
|
|
|
|
*result = 0;
|
|
|
|
if (!_fixSize && !_isFullScreen() && !_isMaximized()) {
|
|
|
|
if (left && top) {
|
|
|
|
*result = HTTOPLEFT;
|
|
|
|
} else if (left && bottom) {
|
|
|
|
*result = HTBOTTOMLEFT;
|
|
|
|
} else if (right && top) {
|
|
|
|
*result = HTTOPRIGHT;
|
|
|
|
} else if (right && bottom) {
|
|
|
|
*result = HTBOTTOMRIGHT;
|
|
|
|
} else if (left) {
|
|
|
|
*result = HTLEFT;
|
|
|
|
} else if (right) {
|
|
|
|
*result = HTRIGHT;
|
|
|
|
} else if (top) {
|
|
|
|
*result = HTTOP;
|
|
|
|
} else if (bottom) {
|
|
|
|
*result = HTBOTTOM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (0 != *result) {
|
|
|
|
return true;
|
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
if (_hitAppBar()) {
|
2024-03-28 19:18:56 +08:00
|
|
|
*result = HTCAPTION;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
*result = HTCLIENT;
|
|
|
|
return true;
|
2024-04-28 13:03:20 +08:00
|
|
|
} else if (uMsg == WM_NCPAINT) {
|
2024-06-14 17:44:31 +08:00
|
|
|
*result = FALSE;
|
2024-06-23 11:45:49 +08:00
|
|
|
return false;
|
2024-04-28 13:03:20 +08:00
|
|
|
} else if (uMsg == WM_NCACTIVATE) {
|
2024-08-27 17:27:17 +08:00
|
|
|
if (effective() || (!effect().isEmpty() && effect() != "normal")) {
|
2024-08-21 16:12:35 +08:00
|
|
|
return false;
|
|
|
|
}
|
2024-05-05 21:33:47 +08:00
|
|
|
*result = TRUE;
|
|
|
|
return true;
|
2024-04-23 13:41:26 +08:00
|
|
|
} else if (_isWindows11OrGreater && (uMsg == WM_NCLBUTTONDBLCLK || uMsg == WM_NCLBUTTONDOWN)) {
|
2024-04-11 14:51:43 +08:00
|
|
|
if (_hitMaximizeButton()) {
|
2024-08-27 17:27:17 +08:00
|
|
|
QMouseEvent event = QMouseEvent(QEvent::MouseButtonPress, QPoint(), QPoint(),
|
|
|
|
Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
|
2024-04-11 14:51:43 +08:00
|
|
|
QGuiApplication::sendEvent(_maximizeButton, &event);
|
2024-03-31 10:59:15 +08:00
|
|
|
_setMaximizePressed(true);
|
2024-03-28 19:18:56 +08:00
|
|
|
return true;
|
|
|
|
}
|
2024-04-23 13:41:26 +08:00
|
|
|
} else if (_isWindows11OrGreater && (uMsg == WM_NCLBUTTONUP || uMsg == WM_NCRBUTTONUP)) {
|
2024-04-11 14:51:43 +08:00
|
|
|
if (_hitMaximizeButton()) {
|
2024-08-27 17:27:17 +08:00
|
|
|
QMouseEvent event = QMouseEvent(QEvent::MouseButtonRelease, QPoint(), QPoint(),
|
|
|
|
Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
|
2024-04-11 14:51:43 +08:00
|
|
|
QGuiApplication::sendEvent(_maximizeButton, &event);
|
2024-03-31 10:59:15 +08:00
|
|
|
_setMaximizePressed(false);
|
2024-03-28 19:18:56 +08:00
|
|
|
return true;
|
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
} else if (uMsg == WM_NCRBUTTONDOWN) {
|
2024-03-28 19:18:56 +08:00
|
|
|
if (wParam == HTCAPTION) {
|
2024-05-03 01:54:38 +08:00
|
|
|
auto pos = window()->position();
|
|
|
|
auto offset = window()->mapFromGlobal(QCursor::pos());
|
|
|
|
_showSystemMenu(QPoint(pos.x() + offset.x(), pos.y() + offset.y()));
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
} else if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN) {
|
2024-03-28 19:18:56 +08:00
|
|
|
const bool altPressed = ((wParam == VK_MENU) || (::GetKeyState(VK_MENU) < 0));
|
|
|
|
const bool spacePressed = ((wParam == VK_SPACE) || (::GetKeyState(VK_SPACE) < 0));
|
|
|
|
if (altPressed && spacePressed) {
|
|
|
|
auto pos = window()->position();
|
2024-04-11 14:51:43 +08:00
|
|
|
_showSystemMenu(QPoint(pos.x(), qRound(pos.y() + _appbar->height())));
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
} else if (uMsg == WM_SYSCOMMAND) {
|
|
|
|
if (wParam == SC_MINIMIZE) {
|
|
|
|
if (window()->transientParent()) {
|
2024-04-24 10:37:15 +08:00
|
|
|
auto _hwnd = reinterpret_cast<HWND>(window()->transientParent()->winId());
|
|
|
|
::ShowWindow(_hwnd, 2);
|
2024-04-11 14:51:43 +08:00
|
|
|
} else {
|
2024-04-24 10:37:15 +08:00
|
|
|
auto _hwnd = reinterpret_cast<HWND>(window()->winId());
|
|
|
|
::ShowWindow(_hwnd, 2);
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
2024-04-11 14:51:43 +08:00
|
|
|
#else
|
2024-03-28 19:18:56 +08:00
|
|
|
return false;
|
2024-04-11 14:51:43 +08:00
|
|
|
#endif
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
bool FluFrameless::_isMaximized() {
|
2024-03-28 19:18:56 +08:00
|
|
|
return window()->visibility() == QWindow::Maximized;
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
bool FluFrameless::_isFullScreen() {
|
2024-03-28 19:18:56 +08:00
|
|
|
return window()->visibility() == QWindow::FullScreen;
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::_showSystemMenu(QPoint point) {
|
2024-03-28 19:18:56 +08:00
|
|
|
#ifdef Q_OS_WIN
|
2024-05-03 01:54:38 +08:00
|
|
|
QScreen *screen = window()->screen();
|
|
|
|
if (!screen) {
|
|
|
|
screen = QGuiApplication::primaryScreen();
|
|
|
|
}
|
|
|
|
if (!screen) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const QPoint origin = screen->geometry().topLeft();
|
2024-08-27 17:27:17 +08:00
|
|
|
auto nativePos =
|
|
|
|
QPointF(QPointF(point - origin) * window()->devicePixelRatio()).toPoint() + origin;
|
2024-03-28 19:18:56 +08:00
|
|
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
2024-04-11 14:51:43 +08:00
|
|
|
auto hMenu = ::GetSystemMenu(hwnd, FALSE);
|
|
|
|
if (_isMaximized() || _isFullScreen()) {
|
|
|
|
::EnableMenuItem(hMenu, SC_MOVE, MFS_DISABLED);
|
|
|
|
::EnableMenuItem(hMenu, SC_RESTORE, MFS_ENABLED);
|
|
|
|
} else {
|
|
|
|
::EnableMenuItem(hMenu, SC_MOVE, MFS_ENABLED);
|
|
|
|
::EnableMenuItem(hMenu, SC_RESTORE, MFS_DISABLED);
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
if (!_fixSize && !_isMaximized() && !_isFullScreen()) {
|
|
|
|
::EnableMenuItem(hMenu, SC_SIZE, MFS_ENABLED);
|
|
|
|
::EnableMenuItem(hMenu, SC_MAXIMIZE, MFS_ENABLED);
|
|
|
|
} else {
|
|
|
|
::EnableMenuItem(hMenu, SC_SIZE, MFS_DISABLED);
|
|
|
|
::EnableMenuItem(hMenu, SC_MAXIMIZE, MFS_DISABLED);
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
2024-08-27 17:27:17 +08:00
|
|
|
const int result = ::TrackPopupMenu(
|
|
|
|
hMenu,
|
|
|
|
(TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
|
|
|
|
nativePos.x(), nativePos.y(), 0, hwnd, nullptr);
|
2024-05-11 21:45:45 +08:00
|
|
|
if (result) {
|
2024-03-28 19:18:56 +08:00
|
|
|
::PostMessageW(hwnd, WM_SYSCOMMAND, result, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
bool FluFrameless::_hitAppBar() {
|
|
|
|
for (int i = 0; i <= _hitTestList.size() - 1; ++i) {
|
|
|
|
auto item = _hitTestList.at(i);
|
|
|
|
if (containsCursorToItem(item)) {
|
2024-03-28 19:18:56 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2024-04-11 14:51:43 +08:00
|
|
|
if (containsCursorToItem(_appbar)) {
|
2024-03-28 19:18:56 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
bool FluFrameless::_hitMaximizeButton() {
|
|
|
|
if (containsCursorToItem(_maximizeButton)) {
|
2024-03-28 19:18:56 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::_setMaximizePressed(bool val) {
|
2024-05-17 21:19:10 +08:00
|
|
|
if (_maximizeButton) {
|
2024-05-10 19:20:01 +08:00
|
|
|
_maximizeButton->setProperty("down", val);
|
|
|
|
}
|
2024-03-31 10:59:15 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::_setMaximizeHovered(bool val) {
|
2024-05-17 21:19:10 +08:00
|
|
|
if (_maximizeButton) {
|
2024-05-10 19:20:01 +08:00
|
|
|
_maximizeButton->setProperty("hover", val);
|
|
|
|
}
|
2024-03-31 10:59:15 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::_updateCursor(int edges) {
|
2024-03-28 19:18:56 +08:00
|
|
|
switch (edges) {
|
2024-08-27 17:27:17 +08:00
|
|
|
case 0:
|
|
|
|
window()->setCursor(Qt::ArrowCursor);
|
|
|
|
break;
|
|
|
|
case Qt::LeftEdge:
|
|
|
|
case Qt::RightEdge:
|
|
|
|
window()->setCursor(Qt::SizeHorCursor);
|
|
|
|
break;
|
|
|
|
case Qt::TopEdge:
|
|
|
|
case Qt::BottomEdge:
|
|
|
|
window()->setCursor(Qt::SizeVerCursor);
|
|
|
|
break;
|
|
|
|
case Qt::LeftEdge | Qt::TopEdge:
|
|
|
|
case Qt::RightEdge | Qt::BottomEdge:
|
|
|
|
window()->setCursor(Qt::SizeFDiagCursor);
|
|
|
|
break;
|
|
|
|
case Qt::RightEdge | Qt::TopEdge:
|
|
|
|
case Qt::LeftEdge | Qt::BottomEdge:
|
|
|
|
window()->setCursor(Qt::SizeBDiagCursor);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
[[maybe_unused]] void FluFrameless::showFullScreen() {
|
2024-03-28 19:18:56 +08:00
|
|
|
window()->showFullScreen();
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::showMaximized() {
|
2024-03-28 19:18:56 +08:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
2024-04-11 14:51:43 +08:00
|
|
|
::ShowWindow(hwnd, 3);
|
2024-03-28 19:18:56 +08:00
|
|
|
#else
|
2024-04-23 13:41:26 +08:00
|
|
|
window()->setVisibility(QQuickWindow::Maximized);
|
2024-03-28 19:18:56 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
[[maybe_unused]] void FluFrameless::showMinimized() {
|
2024-04-23 13:41:26 +08:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
|
|
|
::ShowWindow(hwnd, 2);
|
|
|
|
#else
|
|
|
|
window()->setVisibility(QQuickWindow::Minimized);
|
|
|
|
#endif
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::showNormal() {
|
2024-04-23 13:41:26 +08:00
|
|
|
window()->setVisibility(QQuickWindow::Windowed);
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::setHitTestVisible(QQuickItem *val) {
|
|
|
|
if (!_hitTestList.contains(val)) {
|
2024-03-31 10:59:15 +08:00
|
|
|
_hitTestList.append(val);
|
|
|
|
}
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
void FluFrameless::_setWindowTopmost(bool topmost) {
|
2024-03-28 19:18:56 +08:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
HWND hwnd = reinterpret_cast<HWND>(window()->winId());
|
2024-04-11 14:51:43 +08:00
|
|
|
if (topmost) {
|
2024-03-28 19:18:56 +08:00
|
|
|
::SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
2024-04-11 14:51:43 +08:00
|
|
|
} else {
|
2024-03-28 19:18:56 +08:00
|
|
|
::SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
}
|
|
|
|
#else
|
2024-08-27 17:27:17 +08:00
|
|
|
window()->setFlag(Qt::WindowStaysOnTopHint, topmost);
|
2024-03-28 19:18:56 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-04-11 14:51:43 +08:00
|
|
|
bool FluFrameless::eventFilter(QObject *obj, QEvent *ev) {
|
2024-03-28 19:18:56 +08:00
|
|
|
#ifndef Q_OS_WIN
|
|
|
|
switch (ev->type()) {
|
2024-08-27 17:27:17 +08:00
|
|
|
case QEvent::MouseButtonPress:
|
|
|
|
if (_edges != 0) {
|
|
|
|
QMouseEvent *event = static_cast<QMouseEvent *>(ev);
|
|
|
|
if (event->button() == Qt::LeftButton) {
|
|
|
|
_updateCursor(_edges);
|
|
|
|
window()->startSystemResize(Qt::Edges(_edges));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (_hitAppBar()) {
|
|
|
|
qint64 clickTimer = QDateTime::currentMSecsSinceEpoch();
|
|
|
|
qint64 offset = clickTimer - this->_clickTimer;
|
|
|
|
this->_clickTimer = clickTimer;
|
|
|
|
if (offset < 300) {
|
|
|
|
if (_isMaximized()) {
|
|
|
|
showNormal();
|
|
|
|
} else {
|
|
|
|
showMaximized();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
window()->startSystemMove();
|
2024-04-03 13:24:30 +08:00
|
|
|
}
|
|
|
|
}
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
break;
|
2024-08-27 17:27:17 +08:00
|
|
|
case QEvent::MouseButtonRelease:
|
|
|
|
_edges = 0;
|
2024-03-28 19:18:56 +08:00
|
|
|
break;
|
2024-08-27 17:27:17 +08:00
|
|
|
case QEvent::MouseMove: {
|
|
|
|
if (_isMaximized() || _isFullScreen()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (_fixSize) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
QMouseEvent *event = static_cast<QMouseEvent *>(ev);
|
|
|
|
QPoint p =
|
|
|
|
# if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
|
|
event->pos();
|
|
|
|
# else
|
|
|
|
event->position().toPoint();
|
|
|
|
# endif
|
|
|
|
if (p.x() >= _margins && p.x() <= (window()->width() - _margins) && p.y() >= _margins &&
|
|
|
|
p.y() <= (window()->height() - _margins)) {
|
|
|
|
if (_edges != 0) {
|
|
|
|
_edges = 0;
|
|
|
|
_updateCursor(_edges);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_edges = 0;
|
|
|
|
if (p.x() < _margins) {
|
|
|
|
_edges |= Qt::LeftEdge;
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
2024-08-27 17:27:17 +08:00
|
|
|
if (p.x() > (window()->width() - _margins)) {
|
|
|
|
_edges |= Qt::RightEdge;
|
|
|
|
}
|
|
|
|
if (p.y() < _margins) {
|
|
|
|
_edges |= Qt::TopEdge;
|
|
|
|
}
|
|
|
|
if (p.y() > (window()->height() - _margins)) {
|
|
|
|
_edges |= Qt::BottomEdge;
|
|
|
|
}
|
|
|
|
_updateCursor(_edges);
|
2024-03-28 19:18:56 +08:00
|
|
|
break;
|
|
|
|
}
|
2024-08-27 17:27:17 +08:00
|
|
|
default:
|
|
|
|
break;
|
2024-03-28 19:18:56 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return QObject::eventFilter(obj, ev);
|
|
|
|
}
|