Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "BaseFramelessWindow.hpp"
- #include <QtWidgets/qapplication.h>
- #ifdef Q_OS_WIN
- #include <windows.h>
- #include <windowsx.h>
- #include <WinUser.h>
- #include <gdiplus.h>
- #include <GdiPlusColor.h>
- #include <dwmapi.h>
- #include <objidl.h>
- #pragma comment(lib, "Dwmapi.lib")
- #pragma comment(lib, "user32.lib")
- namespace Utils {
- inline bool isMaximized(HWND hwnd)
- {
- WINDOWPLACEMENT placement;
- if (!::GetWindowPlacement(hwnd, &placement)) {
- return false;
- }
- return placement.showCmd == SW_MAXIMIZE;
- }
- inline void adjustMaximizedClientRect(HWND window, RECT& rect)
- {
- if (!isMaximized(window)) {
- return;
- }
- auto monitor = ::MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
- if (!monitor) {
- return;
- }
- MONITORINFO monitor_info {};
- monitor_info.cbSize = sizeof(monitor_info);
- if (!::GetMonitorInfoW(monitor, &monitor_info)) {
- return;
- }
- // When maximized, make the client area fill just the monitor (without task bar) rect,
- // not the whole window rect which extends beyond the monitor.
- rect = monitor_info.rcWork;
- }
- inline bool isCompositionEnabled()
- {
- auto compositionEnabled = FALSE;
- auto success = ::DwmIsCompositionEnabled(&compositionEnabled) == S_OK;
- return compositionEnabled && success;
- }
- inline int selectBorderlessStyle()
- {
- constexpr auto AeroBorderless = WS_POPUP | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX;
- constexpr auto BasicBorderless = WS_POPUP | WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX;
- return isCompositionEnabled() ? AeroBorderless : BasicBorderless;
- }
- inline void initializeBorderless(HWND window)
- {
- ::SetWindowLongPtr(window, GWL_STYLE, static_cast<LONG>(selectBorderlessStyle()));
- ::SetWindowPos(window, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
- }
- } /* namespace Utils */
- BaseFramelessWindow::BaseFramelessWindow(QWidget* parent)
- : QMainWindow(parent)
- , m_titlebar(Q_NULLPTR)
- {
- setWindowFlags(windowFlags() | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint | Qt::FramelessWindowHint);
- Utils::initializeBorderless((HWND)winId());
- const MARGINS shadow = { 1, 1, 1, 1 };
- DwmExtendFrameIntoClientArea(HWND(winId()), &shadow);
- }
- bool BaseFramelessWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
- {
- // Workaround for known bug -> check Qt forum : https://forum.qt.io/topic/93141/qtablewidget-itemselectionchanged/13
- #if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
- MSG* msg = *reinterpret_cast<MSG**>(message);
- #else
- MSG* msg = reinterpret_cast<MSG*>(message);
- #endif
- switch (msg->message) {
- case WM_NCCALCSIZE: {
- if (msg->wParam == TRUE) {
- auto& params = *reinterpret_cast<NCCALCSIZE_PARAMS*>(msg->lParam);
- Utils::adjustMaximizedClientRect(msg->hwnd, params.rgrc[0]);
- }
- *result = WVR_REDRAW;
- return true;
- }
- case WM_NCHITTEST: {
- *result = 0;
- const LONG borderWidth = 5; // in pixels
- RECT winrect;
- GetWindowRect(reinterpret_cast<HWND>(winId()), &winrect);
- long x = GET_X_LPARAM(msg->lParam);
- long y = GET_Y_LPARAM(msg->lParam);
- auto resizeWidth = minimumWidth() != maximumWidth();
- auto 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;
- // *result still equals 0, that means the cursor locate OUTSIDE the frame area
- // but it may locate in titlebar area
- if (!m_titlebar)
- return false;
- // support highdpi
- qreal dpr = this->devicePixelRatioF();
- QPoint pos = m_titlebar->mapFromGlobal(QPoint(x / dpr, y / dpr));
- if (!m_titlebar->rect().contains(pos))
- return false;
- QWidget* child = m_titlebar->childAt(pos);
- if (!child) {
- *result = HTCAPTION;
- return true;
- }
- return false;
- }
- case WM_NCRBUTTONUP: {
- long x = GET_X_LPARAM(msg->lParam);
- long y = GET_Y_LPARAM(msg->lParam);
- // Support highdpi
- qreal dpr = this->devicePixelRatioF();
- QPoint pos = m_titlebar->mapFromGlobal(QPoint(x / dpr, y / dpr));
- if (m_titlebar->rect().contains(pos)) {
- HMENU menu = GetSystemMenu(msg->hwnd, FALSE);
- TrackPopupMenu(menu, 0, x, y, 0, msg->hwnd, nullptr);
- }
- return true;
- }
- case WM_GETMINMAXINFO: {
- MINMAXINFO* mmi = reinterpret_cast<MINMAXINFO*>(msg->lParam);
- if (Utils::isMaximized(msg->hwnd)) {
- RECT window_rect;
- if (!GetWindowRect(msg->hwnd, &window_rect)) {
- return false;
- }
- HMONITOR monitor = MonitorFromRect(&window_rect, MONITOR_DEFAULTTONULL);
- if (!monitor) {
- return false;
- }
- MONITORINFO monitor_info = { 0 };
- monitor_info.cbSize = sizeof(monitor_info);
- GetMonitorInfo(monitor, &monitor_info);
- RECT work_area = monitor_info.rcWork;
- RECT monitor_rect = monitor_info.rcMonitor;
- mmi->ptMaxPosition.x = abs(work_area.left - monitor_rect.left);
- mmi->ptMaxPosition.y = abs(work_area.top - monitor_rect.top);
- mmi->ptMaxSize.x = abs(work_area.right - work_area.left);
- mmi->ptMaxSize.y = abs(work_area.bottom - work_area.top);
- mmi->ptMaxTrackSize.x = mmi->ptMaxSize.x;
- mmi->ptMaxTrackSize.y = mmi->ptMaxSize.y;
- *result = 1;
- }
- return false;
- }
- case WM_NCACTIVATE: {
- if (!Utils::isCompositionEnabled()) {
- // Prevents window frame reappearing on window activation
- // in "basic" theme, where no aero shadow is present.
- *result = 1;
- return true;
- }
- }
- case WM_SIZE: {
- RECT winrect;
- GetClientRect(msg->hwnd, &winrect);
- WINDOWPLACEMENT wp;
- wp.length = sizeof(WINDOWPLACEMENT);
- GetWindowPlacement(msg->hwnd, &wp);
- if (this) {
- if (wp.showCmd == SW_MAXIMIZE) {
- ::SetWindowPos(reinterpret_cast<HWND>(winId()), Q_NULLPTR, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
- }
- }
- return false;
- }
- }
- return QWidget::nativeEvent(eventType, message, result);
- }
- #endif /* Q_OS_WIN */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement