WindowsFramelessWindow.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #include "WindowsFramelessWindow.h"
  2. #include "WindowsWindowEffect.h"
  3. #include "titlebar/TitleBar.h"
  4. #include "utils/Win32Utils.h"
  5. #include <QWindow>
  6. #include <QtWin>
  7. #include <QApplication>
  8. #include <QCloseEvent>
  9. #include <QScreen>
  10. #include <QDesktopWidget>
  11. #include <QDebug>
  12. constexpr int BORDER_WIDTH = 5;
  13. WindowsFramelessWindow::WindowsFramelessWindow(QWidget *parent) : QMainWindow(parent)
  14. {
  15. Q_INIT_RESOURCE(qframelesswindow);
  16. windowEffect = new WindowsWindowEffect(this);
  17. titleBar = new TitleBar(this);
  18. isResizeEnabled = true;
  19. // remove window border
  20. if (!Win32Utils::isWin7()) {
  21. setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);
  22. } else {
  23. setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
  24. }
  25. // add DWM shadow and window animation
  26. windowEffect->addWindowAnimation((HWND)this->winId());
  27. if (effectType() == "AcrylicWindow") {
  28. windowEffect->addShadowEffect((HWND)this->winId());
  29. }
  30. connect(this->windowHandle(), &QWindow::screenChanged, this, &WindowsFramelessWindow::onScreenChanged);
  31. resize(500, 500);
  32. titleBar->raise();
  33. }
  34. void WindowsFramelessWindow::setTitleBar(TitleBar *tBar)
  35. {
  36. if (tBar != titleBar) {
  37. titleBar->deleteLater();
  38. titleBar = tBar;
  39. titleBar->setParent(this);
  40. titleBar->raise();
  41. }
  42. }
  43. void WindowsFramelessWindow::setResizeEnabled(bool isEnabled)
  44. {
  45. isResizeEnabled = isEnabled;
  46. }
  47. bool WindowsFramelessWindow::getResizeEnabled() const
  48. {
  49. return isResizeEnabled;
  50. }
  51. WindowsWindowEffect *WindowsFramelessWindow::getWindowEffect() const
  52. {
  53. return windowEffect;
  54. }
  55. TitleBar *WindowsFramelessWindow::getTitleBar() const
  56. {
  57. return titleBar;
  58. }
  59. void WindowsFramelessWindow::onScreenChanged(QScreen *screen)
  60. {
  61. HWND hWnd = (HWND)this->windowHandle()->winId();
  62. SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
  63. }
  64. void WindowsFramelessWindow::resizeEvent(QResizeEvent *event)
  65. {
  66. QWidget::resizeEvent(event);
  67. titleBar->resize(this->width(), titleBar->height());
  68. }
  69. /// Handle the Windows message
  70. bool WindowsFramelessWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
  71. {
  72. MSG *msg = static_cast<MSG *>(message);
  73. if (!msg->hwnd) {
  74. return QWidget::nativeEvent(eventType, message, result);
  75. }
  76. switch (msg->message) {
  77. case WM_NCHITTEST: {
  78. if (isResizeEnabled) {
  79. QPoint pos = QCursor::pos();
  80. int xPos = pos.x() - this->x();
  81. int yPos = pos.y() - this->y();
  82. int w = this->width();
  83. int h = this->height();
  84. bool lx = (xPos < BORDER_WIDTH);
  85. bool rx = (xPos > w - BORDER_WIDTH);
  86. bool ty = (yPos < BORDER_WIDTH);
  87. bool by = (yPos > h - BORDER_WIDTH);
  88. if (lx && ty) {
  89. *result = HTTOPLEFT;
  90. return true;
  91. } else if (rx && by) {
  92. *result = HTBOTTOMRIGHT;
  93. return true;
  94. } else if (rx && ty) {
  95. *result = HTTOPRIGHT;
  96. return true;
  97. } else if (lx && by) {
  98. *result = HTBOTTOMLEFT;
  99. return true;
  100. } else if (ty) {
  101. *result = HTTOP;
  102. return true;
  103. } else if (by) {
  104. *result = HTBOTTOM;
  105. return true;
  106. } else if (lx) {
  107. *result = HTLEFT;
  108. return true;
  109. } else if (rx) {
  110. *result = HTRIGHT;
  111. return true;
  112. }
  113. }
  114. } break;
  115. case WM_NCCALCSIZE: {
  116. RECT rc;
  117. if (msg->wParam) {
  118. rc = ((LPNCCALCSIZE_PARAMS)msg->lParam)->rgrc[0];
  119. } else {
  120. rc = *(LPRECT)msg->lParam;
  121. }
  122. bool isMax = Win32Utils::isMaximized(msg->hwnd);
  123. bool isFull = Win32Utils::isFullScreen(msg->hwnd);
  124. // adjust the size of client rect
  125. if (isMax && !isFull) {
  126. int ty = Win32Utils::getResizeBorderThickness(msg->hwnd, false);
  127. rc.top += ty;
  128. rc.bottom -= ty;
  129. int tx = Win32Utils::getResizeBorderThickness(msg->hwnd, true);
  130. rc.left += tx;
  131. rc.right -= tx;
  132. }
  133. // handle the situation that an auto-hide taskbar is enabled
  134. if ((isMax || isFull) && Win32Utils::Taskbar::isAutoHide()) {
  135. Win32Utils::Taskbar::Position position = Win32Utils::Taskbar::getPosition(msg->hwnd);
  136. if (position == Win32Utils::Taskbar::TOP) {
  137. rc.top += Win32Utils::Taskbar::AUTO_HIDE_THICKNESS;
  138. } else if (position == Win32Utils::Taskbar::BOTTOM) {
  139. rc.bottom -= Win32Utils::Taskbar::AUTO_HIDE_THICKNESS;
  140. } else if (position == Win32Utils::Taskbar::LEFT) {
  141. rc.left += Win32Utils::Taskbar::AUTO_HIDE_THICKNESS;
  142. } else if (position == Win32Utils::Taskbar::RIGHT) {
  143. rc.right -= Win32Utils::Taskbar::AUTO_HIDE_THICKNESS;
  144. }
  145. }
  146. if (!msg->wParam) {
  147. *result = 0;
  148. } else {
  149. *result = WVR_REDRAW;
  150. }
  151. return true;
  152. } break;
  153. case WM_GETMINMAXINFO: {
  154. //解决QT无边框窗体最大化遮盖Windows任务栏问题
  155. if (this->isMaximized()) {
  156. int index = QApplication::desktop()->screenNumber(this);
  157. const QRect rc = QApplication::desktop()->availableGeometry(index);
  158. MINMAXINFO *p = (MINMAXINFO *)(msg->lParam);
  159. p->ptMaxPosition.x = 0;
  160. p->ptMaxPosition.y = 0;
  161. p->ptMaxSize.x = rc.width();
  162. p->ptMaxSize.y = rc.height();
  163. *result = ::DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
  164. }
  165. }
  166. }
  167. return QWidget::nativeEvent(eventType, message, result);
  168. }
  169. AcrylicWindow::AcrylicWindow(QWidget *parent) : WindowsFramelessWindow(parent), closedByKey(false)
  170. {
  171. QtWin::enableBlurBehindWindow(this);
  172. setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
  173. WindowsWindowEffect *windowEffect = getWindowEffect();
  174. windowEffect->addWindowAnimation((HWND)this->winId());
  175. if (Win32Utils::isWin7()) {
  176. windowEffect->addShadowEffect((HWND)this->winId());
  177. windowEffect->setAeroEffect((HWND)this->winId());
  178. } else {
  179. windowEffect->setAcrylicEffect((HWND)this->winId());
  180. if (Win32Utils::isGreaterEqualWin11()) {
  181. windowEffect->addShadowEffect((HWND)this->winId());
  182. }
  183. }
  184. setStyleSheet("AcrylicWindow{background:transparent}");
  185. }
  186. QString AcrylicWindow::effectType() const
  187. {
  188. return "AcrylicWindow";
  189. }
  190. void AcrylicWindow::closeEvent(QCloseEvent *event)
  191. {
  192. if (!closedByKey || QApplication::quitOnLastWindowClosed()) {
  193. closedByKey = false;
  194. return WindowsFramelessWindow::closeEvent(event);
  195. }
  196. // system tray icon
  197. closedByKey = false;
  198. this->hide();
  199. }
  200. bool AcrylicWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
  201. {
  202. MSG *msg = static_cast<MSG *>(message);
  203. if (msg->message == WM_SYSKEYDOWN) {
  204. if (msg->wParam == VK_F4) {
  205. closedByKey = true;
  206. QCloseEvent clsEvt;
  207. QApplication::sendEvent(this, &clsEvt);
  208. *result = 0;
  209. return false;
  210. }
  211. }
  212. return WindowsFramelessWindow::nativeEvent(eventType, message, result);
  213. }