WindowsFramelessWidget.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include "WindowsFramelessWidget.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. constexpr int BORDER_WIDTH = 5;
  11. WindowsFramelessWidget::WindowsFramelessWidget(QWidget *parent) : QWidget(parent)
  12. {
  13. Q_INIT_RESOURCE(qframelesswindow);
  14. windowEffect = new WindowsWindowEffect(this);
  15. titleBar = new TitleBar(this);
  16. isResizeEnabled = true;
  17. // remove window border
  18. if (!Win32Utils::isWin7()) {
  19. setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);
  20. } else {
  21. setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
  22. }
  23. // add DWM shadow and window animation
  24. windowEffect->addWindowAnimation((HWND)this->winId());
  25. if (effectType() == "AcrylicWindow") {
  26. windowEffect->addShadowEffect((HWND)this->winId());
  27. }
  28. connect(this->windowHandle(), &QWindow::screenChanged, this, &WindowsFramelessWidget::onScreenChanged);
  29. resize(500, 500);
  30. titleBar->raise();
  31. }
  32. void WindowsFramelessWidget::setTitleBar(TitleBar *tBar)
  33. {
  34. if (tBar != titleBar) {
  35. titleBar->deleteLater();
  36. titleBar = tBar;
  37. titleBar->setParent(this);
  38. titleBar->raise();
  39. }
  40. }
  41. void WindowsFramelessWidget::setResizeEnabled(bool isEnabled)
  42. {
  43. isResizeEnabled = isEnabled;
  44. }
  45. bool WindowsFramelessWidget::getResizeEnabled() const
  46. {
  47. return isResizeEnabled;
  48. }
  49. WindowsWindowEffect *WindowsFramelessWidget::getWindowEffect() const
  50. {
  51. return windowEffect;
  52. }
  53. TitleBar *WindowsFramelessWidget::getTitleBar() const
  54. {
  55. return titleBar;
  56. }
  57. void WindowsFramelessWidget::onScreenChanged(QScreen * /*screen*/)
  58. {
  59. HWND hWnd = (HWND)this->windowHandle()->winId();
  60. SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
  61. }
  62. void WindowsFramelessWidget::resizeEvent(QResizeEvent *event)
  63. {
  64. QWidget::resizeEvent(event);
  65. titleBar->resize(this->width(), titleBar->height());
  66. }
  67. /// Handle the Windows message
  68. bool WindowsFramelessWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
  69. {
  70. MSG *msg = static_cast<MSG *>(message);
  71. if (!msg->hwnd) {
  72. return QWidget::nativeEvent(eventType, message, result);
  73. }
  74. switch (msg->message) {
  75. case WM_NCHITTEST: {
  76. if (isResizeEnabled) {
  77. QPoint pos = QCursor::pos();
  78. int xPos = pos.x() - this->x();
  79. int yPos = pos.y() - this->y();
  80. int w = this->width();
  81. int h = this->height();
  82. bool lx = (xPos < BORDER_WIDTH);
  83. bool rx = (xPos > w - BORDER_WIDTH);
  84. bool ty = (yPos < BORDER_WIDTH);
  85. bool by = (yPos > h - BORDER_WIDTH);
  86. if (lx && ty) {
  87. *result = HTTOPLEFT;
  88. return true;
  89. } else if (rx && by) {
  90. *result = HTBOTTOMRIGHT;
  91. return true;
  92. } else if (rx && ty) {
  93. *result = HTTOPRIGHT;
  94. return true;
  95. } else if (lx && by) {
  96. *result = HTBOTTOMLEFT;
  97. return true;
  98. } else if (ty) {
  99. *result = HTTOP;
  100. return true;
  101. } else if (by) {
  102. *result = HTBOTTOM;
  103. return true;
  104. } else if (lx) {
  105. *result = HTLEFT;
  106. return true;
  107. } else if (rx) {
  108. *result = HTRIGHT;
  109. return true;
  110. }
  111. }
  112. } break;
  113. case WM_NCCALCSIZE: {
  114. RECT rc;
  115. if (msg->wParam) {
  116. rc = ((LPNCCALCSIZE_PARAMS)msg->lParam)->rgrc[0];
  117. } else {
  118. rc = *(LPRECT)msg->lParam;
  119. }
  120. bool isMax = Win32Utils::isMaximized(msg->hwnd);
  121. bool isFull = Win32Utils::isFullScreen(msg->hwnd);
  122. // adjust the size of client rect
  123. if (isMax && !isFull) {
  124. int ty = Win32Utils::getResizeBorderThickness(msg->hwnd, false);
  125. rc.top += ty;
  126. rc.bottom -= ty;
  127. int tx = Win32Utils::getResizeBorderThickness(msg->hwnd, true);
  128. rc.left += tx;
  129. rc.right -= tx;
  130. }
  131. // handle the situation that an auto-hide taskbar is enabled
  132. if ((isMax || isFull) && Win32Utils::Taskbar::isAutoHide()) {
  133. Win32Utils::Taskbar::Position position = Win32Utils::Taskbar::getPosition(msg->hwnd);
  134. if (position == Win32Utils::Taskbar::TOP) {
  135. rc.top += Win32Utils::Taskbar::AUTO_HIDE_THICKNESS;
  136. } else if (position == Win32Utils::Taskbar::BOTTOM) {
  137. rc.bottom -= Win32Utils::Taskbar::AUTO_HIDE_THICKNESS;
  138. } else if (position == Win32Utils::Taskbar::LEFT) {
  139. rc.left += Win32Utils::Taskbar::AUTO_HIDE_THICKNESS;
  140. } else if (position == Win32Utils::Taskbar::RIGHT) {
  141. rc.right -= Win32Utils::Taskbar::AUTO_HIDE_THICKNESS;
  142. }
  143. }
  144. if (!msg->wParam) {
  145. *result = 0;
  146. } else {
  147. *result = WVR_REDRAW;
  148. }
  149. return true;
  150. } break;
  151. }
  152. return QWidget::nativeEvent(eventType, message, result);
  153. }