From ccab0fb88cc562614a97538e76b02214e5d0537d Mon Sep 17 00:00:00 2001 From: dreamsourcelabTAI Date: Wed, 17 Apr 2024 17:19:30 +0800 Subject: [PATCH] fix: the shadow is not displayed in windows 10 --- DSView/pv/winnativewidget.cpp | 303 ++++++++++++++++++++-------------- DSView/pv/winnativewidget.h | 15 +- DSView/pv/winshadow.cpp | 52 +++--- DSView/pv/winshadow.h | 28 +++- 4 files changed, 232 insertions(+), 166 deletions(-) diff --git a/DSView/pv/winnativewidget.cpp b/DSView/pv/winnativewidget.cpp index 74231edc..f61f6bb6 100644 --- a/DSView/pv/winnativewidget.cpp +++ b/DSView/pv/winnativewidget.cpp @@ -37,9 +37,8 @@ #include #include "log.h" -#include "../config.h" -#include "winshadow.h" #include "mainframe.h" +#include "dsvdef.h" #define FIXED_WIDTH(widget) (widget->minimumWidth() >= widget->maximumWidth()) #define FIXED_HEIGHT(widget) (widget->minimumHeight() >= widget->maximumHeight()) @@ -52,9 +51,11 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, const int height, QColor backColor) { _childWindow = nullptr; - childWidget = nullptr; + _childWidget = nullptr; _hWnd = NULL; _event_callback = NULL; + _is_lose_foreground = false; + _is_ncdown = false; _titleBarWidget = NULL; _is_native_border = IsWin11OrGreater(); @@ -105,6 +106,7 @@ WinNativeWidget::WinNativeWidget(const int x, const int y, const int width, if (!_is_native_border){ _shadow = new WinShadow(_hWnd, NULL); _shadow->createWinId(); + _shadow->SetCallback(this); } } @@ -118,7 +120,7 @@ WinNativeWidget::~WinNativeWidget() void WinNativeWidget::SetChildWidget(MainFrame *w) { - childWidget = w; + _childWidget = w; _childWindow = NULL; if (w != NULL){ @@ -150,28 +152,40 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam } switch (message) - { + { case WM_SYSCOMMAND: { if (wParam == SC_KEYMENU) { - RECT winrect; - GetWindowRect(hWnd, &winrect); - TrackPopupMenu(GetSystemMenu(hWnd, false), TPM_TOPALIGN | TPM_LEFTALIGN, winrect.left + 5, winrect.top + 5, 0, hWnd, NULL); + RECT rc; + GetWindowRect(hWnd, &rc); + TrackPopupMenu(GetSystemMenu(hWnd, false), TPM_TOPALIGN | TPM_LEFTALIGN, + rc.left + 5, rc.top + 5, 0, hWnd, NULL); } - break;; + break; } case WM_KEYDOWN: { //enable the hot key. QKeyEvent keyEvent(QEvent::KeyPress, (int)wParam, 0); - QApplication::sendEvent(self->childWidget->GetBodyView(), &keyEvent); + QApplication::sendEvent(self->_childWidget->GetBodyView(), &keyEvent); break; } case WM_KEYUP: { QKeyEvent keyEvent(QEvent::KeyRelease, (int)wParam, 0); - QApplication::sendEvent(self->childWidget->GetBodyView(), &keyEvent); + QApplication::sendEvent(self->_childWidget->GetBodyView(), &keyEvent); + break; + } + case WM_NCLBUTTONDOWN: + { + self->_is_ncdown = true; + break; + } + case WM_NCLBUTTONUP: + case WM_EXITSIZEMOVE: + { + self->_is_ncdown = false; break; } case WM_NCCALCSIZE: @@ -218,8 +232,8 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam } case WM_CLOSE: { - if (self->childWidget != NULL) { - self->childWidget->close(); + if (self->_childWidget != NULL) { + self->_childWidget->close(); return 0; } break; @@ -278,41 +292,41 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam } break; } - case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: { static int lst_state = -1; - int st = 3; - if (self->IsMaxsized()) - st = 1; - else if (self->IsNormalsized()) - st = 2; - - if (self->childWidget != NULL && self->_shadow && lst_state != st){ - if (st == 2){ - if (self->childWidget->isVisible()){ - self->_shadow->showLater(); - self->showBorder(); - } - } - else { - self->_shadow->hide(); - self->hideBorder(); + + if (self->_childWidget != NULL && self->_is_ncdown == false){ + + int st = 3; + if (self->IsMaxsized()) + st = 1; + else if (self->IsNormalsized()) + st = 2; + + if (lst_state != st || self->_is_lose_foreground) + { + QTimer::singleShot(0, self->_childWidget, [=](){ + self->setShadowStatus(st); + }); } - lst_state = st; + self->_is_lose_foreground = false; + lst_state = st; } + break; } case WM_GETMINMAXINFO: { - if (self->childWidget && self->_hCurrentMonitor) + if (self->_childWidget && self->_hCurrentMonitor) { int maxWidth = 0; int maxHeight = 0; if (self->getMonitorWorkArea(self->_hCurrentMonitor, &maxWidth, &maxHeight)) { - auto gw = self->childWidget; + auto gw = self->_childWidget; int k = self->GetDevicePixelRatio(); QSize minimum = gw->minimumSize(); QSize sizeHint = gw->minimumSizeHint(); @@ -327,97 +341,100 @@ LRESULT CALLBACK WinNativeWidget::WndProc(HWND hWnd, UINT message, WPARAM wParam break; } case WM_NCHITTEST: - { - auto childWidget = self->childWidget; - if (childWidget == NULL) - break; - - - int k = self->GetDevicePixelRatio(); - const LONG borderWidth = 4 * k; - RECT rc; - GetWindowRect(hWnd, &rc); - - int left = rc.left; - int right = rc.right; - int top = rc.top; - int bottom = rc.bottom; - - long x = GET_X_LPARAM(lParam); - long y = GET_Y_LPARAM(lParam); - - // Check if the size can to resize. - if (!self->IsMaxsized()) - { - //bottom left corner - if (x >= left && x < left + borderWidth && - y < bottom && y >= bottom - borderWidth) - { - return HTBOTTOMLEFT; - } - //bottom right corner - if (x < right && x >= right - borderWidth && - y < bottom && y >= bottom - borderWidth) - { - return HTBOTTOMRIGHT; - } - //top left corner - if (x >= left && x < left + borderWidth && - y >= top && y < top + borderWidth) - { - return HTTOPLEFT; - } - //top right corner - if (x < right && x >= right - borderWidth && - y >= top && y < top + borderWidth) - { - return HTTOPRIGHT; - } - //left border - if (x >= left && x < left + borderWidth) - { - return HTLEFT; - } - //right border - if (x < right && x >= right - borderWidth) - { - return HTRIGHT; - } - //bottom border - if (y < bottom && y >= bottom - borderWidth) - { - return HTBOTTOM; - } - //top border - if (y >= top && y < top + borderWidth) - { - return HTTOP; - } - } - - // title bar - if (self->_titleBarWidget) - { - QRect titleRect = self->_titleBarWidget->geometry(); - - int titleWidth = titleRect.width() * k - 55 * k; - int titleHeight = titleRect.height() * k; - - if (x > left + 2 * k && x < left + titleWidth) - { - if (y > top + 2 * k && y < top + titleHeight){ - return HTCAPTION; - } - } + { + if (self->_childWidget != NULL){ + return self->hitTest(hWnd, wParam, lParam); } - - return HTCLIENT; + break; } } return DefWindowProc(hWnd, message, wParam, lParam); } +LRESULT WinNativeWidget::hitTest(HWND hWnd, WPARAM wParam, LPARAM lParam) +{ + int k = GetDevicePixelRatio(); + const LONG borderWidth = 4 * k; + RECT rc; + GetWindowRect(hWnd, &rc); + + int left = rc.left; + int right = rc.right; + int top = rc.top; + int bottom = rc.bottom; + + long x = GET_X_LPARAM(lParam); + long y = GET_Y_LPARAM(lParam); + + // Check if the size can to resize. + if (!IsMaxsized()) + { + //bottom left corner + if (x >= left && x < left + borderWidth && + y < bottom && y >= bottom - borderWidth) + { + return HTBOTTOMLEFT; + } + //bottom right corner + if (x < right && x >= right - borderWidth && + y < bottom && y >= bottom - borderWidth) + { + return HTBOTTOMRIGHT; + } + //top left corner + if (x >= left && x < left + borderWidth && + y >= top && y < top + borderWidth) + { + return HTTOPLEFT; + } + //top right corner + if (x < right && x >= right - borderWidth && + y >= top && y < top + borderWidth) + { + return HTTOPRIGHT; + } + //left border + if (x >= left && x < left + borderWidth) + { + return HTLEFT; + } + //right border + if (x < right && x >= right - borderWidth) + { + return HTRIGHT; + } + //bottom border + if (y < bottom && y >= bottom - borderWidth) + { + return HTBOTTOM; + } + //top border + if (y >= top && y < top + borderWidth) + { + return HTTOP; + } + } + + // title bar + if (_titleBarWidget) + { + QRect titleRect = _titleBarWidget->geometry(); + + int titleWidth = titleRect.width() * k - 55 * k; + int titleHeight = titleRect.height() * k; + + if (x > left + 2 * k && x < left + titleWidth) + { + if (y > top + 2 * k && y < top + titleHeight){ + return HTCAPTION; + } + } + } + + return HTCLIENT; +} + RECT WinNativeWidget::GetMonitorArea(HMONITOR hMonitor, bool isPhysics) { assert(hMonitor); @@ -488,7 +505,7 @@ void WinNativeWidget::ResizeChild() MoveWindow(_childWindow, x, y, w + 1 , h + 1 , 1); MoveWindow(_childWindow, x, y, w , h , 1); - childWidget->updateGeometry(); + _childWidget->updateGeometry(); } } @@ -551,8 +568,8 @@ void WinNativeWidget::UpdateChildDpi() screen = QGuiApplication::primaryScreen(); } - if (screen != NULL && childWidget != NULL){ - childWidget->windowHandle()->setScreen(screen); + if (screen != NULL && _childWidget != NULL){ + _childWidget->windowHandle()->setScreen(screen); if (_shadow != NULL){ _shadow->windowHandle()->setScreen(screen); } @@ -655,7 +672,7 @@ void WinNativeWidget::SetBorderColor(QColor color) pDwmSetWindowAttribute(_hWnd, DWMWINDOWATTRIBUTE_DWMWA_BORDER_COLOR, &COLOR, sizeof(COLOR)); } } - else if (childWidget != NULL){ + else if (_childWidget != NULL){ if (IsMaxsized()){ hideBorder(); } @@ -668,21 +685,21 @@ void WinNativeWidget::SetBorderColor(QColor color) void WinNativeWidget::showBorder() { - if (childWidget != NULL && !_is_native_border){ - childWidget->setObjectName("DSViewFrame"); + if (_childWidget != NULL && !_is_native_border){ + _childWidget->setObjectName("DSViewFrame"); QString borderCss = "#DSViewFrame {border-radius:0px; border:1px solid %1;}"; QString borderStyle = borderCss.arg(_border_color.name()); - childWidget->setStyleSheet(borderStyle); + _childWidget->setStyleSheet(borderStyle); } } void WinNativeWidget::hideBorder() { - if (childWidget != NULL && !_is_native_border){ - childWidget->setObjectName("DSViewFrame"); + if (_childWidget != NULL && !_is_native_border){ + _childWidget->setObjectName("DSViewFrame"); QString borderCss = "#DSViewFrame {border-radius:0px; border:0px solid %1;}"; QString borderStyle = borderCss.arg(_border_color.name()); - childWidget->setStyleSheet(borderStyle); + _childWidget->setStyleSheet(borderStyle); } } @@ -734,4 +751,36 @@ bool WinNativeWidget::IsVisible() return false; } +void WinNativeWidget::OnForeWindowLosed() +{ + _is_lose_foreground = true; +} + +void WinNativeWidget::setShadowStatus(int windowStatus) +{ + if (_shadow == NULL) + return; + + switch (windowStatus) + { + case 1: //maximized + { + _shadow->hideShadow(); + hideBorder(); + break; + } + case 2: //normal + { + _shadow->showLater(); + showBorder(); + break; + } + case 3: //minimized + { + _shadow->hideShadow(); + break; + } + } +} + } diff --git a/DSView/pv/winnativewidget.h b/DSView/pv/winnativewidget.h index 1b2cb6c0..06d30a4a 100644 --- a/DSView/pv/winnativewidget.h +++ b/DSView/pv/winnativewidget.h @@ -32,6 +32,7 @@ #include #include "interface/icallbacks.h" +#include "winshadow.h" #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 @@ -44,13 +45,11 @@ namespace pv { -class WinShadow; class MainFrame; -class WinNativeWidget +class WinNativeWidget: public IShadowCallback { public: - WinNativeWidget(const int x, const int y, const int width, const int heigh, QColor backColor); ~WinNativeWidget(); @@ -105,9 +104,15 @@ private: static RECT GetMonitorArea(HMONITOR hMonitor, bool isPhysics); static bool getMonitorWorkArea(HMONITOR hMonitor, int *outWidth, int *outHeight); + void setShadowStatus(int windowStatus); + + //IShadowCallback + void OnForeWindowLosed() override; + + LRESULT hitTest(HWND hWnd, WPARAM wParam, LPARAM lParam); private: - MainFrame* childWidget; + MainFrame* _childWidget; HWND _childWindow; HWND _hWnd; QWidget *_titleBarWidget; @@ -117,6 +122,8 @@ private: HMONITOR _hCurrentMonitor; WinShadow *_shadow; QColor _border_color; + bool _is_lose_foreground; + bool _is_ncdown; }; } diff --git a/DSView/pv/winshadow.cpp b/DSView/pv/winshadow.cpp index c14e859b..c20f4cdd 100644 --- a/DSView/pv/winshadow.cpp +++ b/DSView/pv/winshadow.cpp @@ -32,9 +32,10 @@ WinShadow::WinShadow(HWND hwnd, QWidget *parent) { m_hwnd = HWND(hwnd); - m_active = true; m_parent = parent; m_scale = 1; + m_bActived = false; + m_callback = NULL; setWindowFlags(Qt::Window | Qt::FramelessWindowHint | (!m_parent ? Qt::Tool : Qt::WindowFlags(0))); @@ -43,11 +44,16 @@ WinShadow::WinShadow(HWND hwnd, QWidget *parent) setAttribute(Qt::WA_TranslucentBackground); m_timer = new QTimer(this); + m_timer->setInterval(100); + m_timer->setSingleShot(true); + + m_checkTimer = new QTimer(this); + m_checkTimer->setInterval(300); + m_checkTimer->start(); + connect(m_timer, &QTimer::timeout, this, &WinShadow::showShadow); connect(this, &WinShadow::showSignal, this, &WinShadow::onMoveSelf); - - m_timer->setInterval(500); - m_timer->setSingleShot(true); + connect(m_checkTimer, &QTimer::timeout, this, &WinShadow::onCheckForeWindow); } void WinShadow::onMoveSelf() @@ -55,10 +61,21 @@ void WinShadow::onMoveSelf() moveShadow(); } +void WinShadow::onCheckForeWindow() +{ + if (m_callback != NULL){ + HWND hw = GetForegroundWindow(); + if (hw != m_hwnd){ + m_callback->OnForeWindowLosed(); + } + } +} + void WinShadow::showLater() -{ +{ m_timer->stop(); m_timer->start(); + m_bActived = true; } void WinShadow::showShadow() @@ -69,9 +86,6 @@ void WinShadow::showShadow() if (!IsWindowEnabled(m_hwnd)) return; - if (GetForegroundWindow() != m_hwnd) - return; - Q_EMIT showSignal(); QWidget::show(); @@ -88,12 +102,7 @@ void WinShadow::hideShadow() return; QWidget::hide(); -} - -void WinShadow::setActive(bool active) -{ - m_active = active; - repaint(); + m_bActived = false; } bool WinShadow::nativeEvent(const QByteArray &eventType, void *message, long *result) @@ -110,7 +119,6 @@ bool WinShadow::nativeEvent(const QByteArray &eventType, void *message, long *re case WA_CLICKACTIVE: { SetForegroundWindow(m_hwnd); - break; } } @@ -120,7 +128,6 @@ bool WinShadow::nativeEvent(const QByteArray &eventType, void *message, long *re { SetForegroundWindow(m_hwnd); *result = MA_NOACTIVATE; - return true; } case WM_NCMOUSEMOVE: @@ -165,7 +172,6 @@ void WinShadow::moveShadow() || IsChild(m_hwnd, active_window)); MoveWindow((HWND)winId(), x, y, w , h , 1); - setActive(isActiveWindow); } } @@ -175,19 +181,7 @@ void WinShadow::paintEvent(QPaintEvent *event) QPainter painter(this); painter.setCompositionMode(QPainter::CompositionMode_Source); - if (!m_active) - { - painter.fillRect(rect(), QColor(0, 0, 0, 1)); - - QRect rect1 = rect().adjusted(shadow_width, shadow_width, -shadow_width, -shadow_width); - - painter.fillRect(rect1, Qt::transparent); - - return; - } - QPixmap radial_gradient = QPixmap(shadow_width * 2, shadow_width * 2); - { radial_gradient.fill(QColor(0, 0, 0, 1)); diff --git a/DSView/pv/winshadow.h b/DSView/pv/winshadow.h index 6c611de9..b6bc9108 100644 --- a/DSView/pv/winshadow.h +++ b/DSView/pv/winshadow.h @@ -31,6 +31,12 @@ namespace pv { +class IShadowCallback +{ +public: + virtual void OnForeWindowLosed()=0; +}; + class WinShadow : public QWidget { Q_OBJECT @@ -46,23 +52,33 @@ public: void showLater(); void hideShadow(); -Q_SIGNALS: + inline bool IsActived(){ + return m_bActived; + } + + inline void SetCallback(IShadowCallback *callback){ + m_callback = callback; + } + +signals: void showSignal(); -public Q_SLOTS: +private slots: void showShadow(); void onMoveSelf(); + void onCheckForeWindow(); private: bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; void paintEvent(QPaintEvent *event) override; - void setActive(bool active); QWidget *m_parent; - QTimer *m_timer; + QTimer *m_timer; + QTimer *m_checkTimer; HWND m_hwnd; - bool m_active; - int m_scale; + int m_scale; + bool m_bActived; + IShadowCallback *m_callback; }; } // namespace pv