// SPDX-FileCopyrightText: 2022 Gary Wang // // SPDX-License-Identifier: MIT #include "framelesswindow.h" #include #include #ifdef _WIN32 #include #endif // _WIN32 FramelessWindow::FramelessWindow(QWidget *parent) : QWidget(parent) , m_centralLayout(new QVBoxLayout(this)) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // The Qt::WindowMinMaxButtonsHint or Qt::WindowMinimizeButtonHint here is to // provide the ability to use Winkey + Up/Down to toggle minimize/maximize. // But a bug introduced in Qt6 that this flag will break the WM_NCHITTEST event. // See: QTBUG-112356 and discussion in https://github.com/BLumia/pineapple-pictures/pull/81 // Thanks @yyc12345 for finding out the source of the issue. this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); #else // There is a bug in Qt 5 that will make pressing Meta+Up cause the app // fullscreen under Windows, see QTBUG-91226 to learn more. // The bug seems no longer exists in Qt 6 (I only tested it under Qt 6.3.0). this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint); #endif // QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_centralLayout->setContentsMargins(QMargins()); } void FramelessWindow::setCentralWidget(QWidget *widget) { if (m_centralWidget) { m_centralLayout->removeWidget(m_centralWidget); m_centralWidget->deleteLater(); } m_centralLayout->addWidget(widget); m_centralWidget = widget; } bool FramelessWindow::nativeEvent(const QByteArray &eventType, void *message, NATIVE_RESULT *result) { #ifdef _WIN32 // https://stackoverflow.com/questions/43505580/qt-windows-resizable-frameless-window // Too lazy to do this now.. just stackoverflow it and did a copy and paste.. Q_UNUSED(eventType) MSG* msg = static_cast(message); if (msg->message == WM_NCHITTEST) { if (isMaximized()) { return false; } *result = 0; const LONG borderWidth = 8; RECT winrect; GetWindowRect(reinterpret_cast(winId()), &winrect); // must be short to correctly work with multiple monitors (negative coordinates) short x = msg->lParam & 0x0000FFFF; short y = (msg->lParam & 0xFFFF0000) >> 16; bool resizeWidth = minimumWidth() != maximumWidth(); bool resizeHeight = minimumHeight() != maximumHeight(); if (resizeWidth) { //left border if (x >= winrect.left && x < winrect.left + borderWidth) { *result = HTLEFT; } //right border if (x < winrect.right && x >= winrect.right - borderWidth) { *result = HTRIGHT; } } if (resizeHeight) { //bottom border if (y < winrect.bottom && y >= winrect.bottom - borderWidth) { *result = HTBOTTOM; } //top border if (y >= winrect.top && y < winrect.top + borderWidth) { *result = HTTOP; } } if (resizeWidth && resizeHeight) { //bottom left corner if (x >= winrect.left && x < winrect.left + borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth) { *result = HTBOTTOMLEFT; } //bottom right corner if (x < winrect.right && x >= winrect.right - borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth) { *result = HTBOTTOMRIGHT; } //top left corner if (x >= winrect.left && x < winrect.left + borderWidth && y >= winrect.top && y < winrect.top + borderWidth) { *result = HTTOPLEFT; } //top right corner if (x < winrect.right && x >= winrect.right - borderWidth && y >= winrect.top && y < winrect.top + borderWidth) { *result = HTTOPRIGHT; } } if (*result != 0) return true; QWidget *action = QApplication::widgetAt(QCursor::pos()); if (action == this) { *result = HTCAPTION; return true; } } return false; #else return QWidget::nativeEvent(eventType, message, result); #endif // _WIN32 }