#include "FramelessView.h" #include #include #include #include #include #include #include #include #pragma comment(lib, "Dwmapi.lib") #pragma comment(lib, "User32.lib") static bool isCompositionEnabled() { BOOL composition_enabled = FALSE; bool success = ::DwmIsCompositionEnabled(&composition_enabled) == S_OK; return composition_enabled && success; } static bool isMaxWin(QWindow* win) { return win->windowState() == Qt::WindowMaximized; } static bool isFullWin(QQuickView* win) { return win->windowState() == Qt::WindowFullScreen; } static bool isFixWin(QQuickView* win) { return win->minimumWidth() == win->maximumWidth() && win->minimumHeight() == win->maximumHeight(); } static long hitTest(RECT winrect, long x, long y, int borderWidth) { if ((x >= winrect.left) && (x < winrect.left + borderWidth) && (y >= winrect.top) && (y < winrect.top + borderWidth)) { return HTTOPLEFT; } else if (x < winrect.right && x >= winrect.right - borderWidth && y >= winrect.top && y < winrect.top + borderWidth) { return HTTOPRIGHT; } else if (x >= winrect.left && x < winrect.left + borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth) { return HTBOTTOMLEFT; } else if (x < winrect.right && x >= winrect.right - borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth) { return HTBOTTOMRIGHT; } else if (x >= winrect.left && x < winrect.left + borderWidth) { return HTLEFT; } else if (x < winrect.right && x >= winrect.right - borderWidth) { return HTRIGHT; } else if (y >= winrect.top && y < winrect.top + borderWidth) { return HTTOP; } else if (y < winrect.bottom && y >= winrect.bottom - borderWidth) { return HTBOTTOM; } else { return 0; } } class FramelessViewPrivate { public: bool m_isMax = false; bool m_isFull = false; bool m_deleteLater = false; bool m_isFirst = true; QQuickItem *m_titleItem = nullptr; }; FramelessView::FramelessView(QWindow *parent) : Super(parent), d(new FramelessViewPrivate) { if(!isCompositionEnabled()){ FluTheme::getInstance()->frameless(false); } if(FluTheme::getInstance()->frameless()){ setFlag(Qt::FramelessWindowHint,true); } setResizeMode(SizeRootObjectToView); setIsMax(windowState() == Qt::WindowMaximized); setIsFull(windowState() == Qt::WindowFullScreen); connect(this, &QWindow::windowStateChanged, this, [=](Qt::WindowState state) { (void)state; setIsMax(windowState() == Qt::WindowMaximized); setIsFull(windowState() == Qt::WindowFullScreen); }); connect(FluTheme::getInstance(),&FluTheme::framelessChanged,this,[=](){ setFlag(Qt::Window,false); setFlag(Qt::Window,true); }); } FramelessView::~FramelessView() { delete d; } void FramelessView::showEvent(QShowEvent *e) { static const MARGINS shadow_state[2] { { 0, 0, 0, 0 }, { 1, 1, 1, 1 } }; ::DwmExtendFrameIntoClientArea((HWND)(winId()), &shadow_state[true]); if(FluTheme::getInstance()->frameless()){ setFlag(Qt::FramelessWindowHint,false); } Super::showEvent(e); } QRect FramelessView::calcCenterGeo(const QRect &screenGeo, const QSize &normalSize) { int w = normalSize.width(); int h = normalSize.height(); int x = screenGeo.x() + (screenGeo.width() - w) / 2; int y = screenGeo.y() + (screenGeo.height() - h) / 2; if (screenGeo.width() < w) { x = screenGeo.x(); w = screenGeo.width(); } if (screenGeo.height() < h) { y = screenGeo.y(); h = screenGeo.height(); } return { x, y, w, h }; } void FramelessView::moveToScreenCenter() { auto geo = calcCenterGeo(screen()->availableGeometry(), size()); if (minimumWidth() > geo.width() || minimumHeight() > geo.height()) { setMinimumSize(geo.size()); } setGeometry(geo); update(); } void FramelessView::closeDeleteLater(){ d->m_deleteLater = true; } bool FramelessView::isMax() const { return d->m_isMax; } bool FramelessView::isFull() const { return d->m_isFull; } QQuickItem *FramelessView::titleItem() const { return d->m_titleItem; } void FramelessView::setIsMax(bool isMax) { if (d->m_isMax == isMax) return; d->m_isMax = isMax; emit isMaxChanged(d->m_isMax); } void FramelessView::setIsFull(bool isFull) { if(d->m_isFull == isFull) return; d->m_isFull = isFull; emit isFullChanged(d->m_isFull); } int count = 1; void FramelessView::setTitleItem(QQuickItem *item) { d->m_titleItem = item; } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) #else bool FramelessView::nativeEvent(const QByteArray &eventType, void *message, long *result) #endif { MSG* msg = static_cast(message); if (!msg || !msg->hwnd) { return false; } if (msg->message == WM_NCHITTEST && FluTheme::getInstance()->frameless()) { RECT winrect; GetWindowRect(HWND(winId()), &winrect); long x = GET_X_LPARAM(msg->lParam); long y = GET_Y_LPARAM(msg->lParam); *result = 0; if (!isMaxWin(this) && !isFullWin(this) && !isFixWin(this)) { *result = hitTest(winrect, x, y, 4); if (0 != *result) { return true; } } }else if (msg->message == WM_NCCALCSIZE && FluTheme::getInstance()->frameless()) { const auto mode = static_cast(msg->wParam); const auto clientRect = mode ? &(reinterpret_cast(msg->lParam)->rgrc[0]) : reinterpret_cast(msg->lParam); if (mode == TRUE) { *result = WVR_REDRAW; if (!isMaxWin(this) && !isFullWin(this)) { if (clientRect->top != 0) { clientRect->top -= 0.1; } } else { if (clientRect->top != 0) { clientRect->top += 0.1; } } return true; } }else if (msg->message == WM_WINDOWPOSCHANGING) { WINDOWPOS* wp = reinterpret_cast(msg->lParam); if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0) { wp->flags |= SWP_NOCOPYBITS; *result = 0; return true; } } return Super::nativeEvent(eventType, message, result); } void FramelessView::resizeEvent(QResizeEvent *e) { Super::resizeEvent(e); } bool FramelessView::event(QEvent *ev) { if (ev->type() == QEvent::Close) { if(d->m_deleteLater){ deleteLater(); ev->setAccepted(false); } } return QQuickWindow::event(ev); }