diff --git a/modules/juce_gui_basics/desktop/juce_Desktop.cpp b/modules/juce_gui_basics/desktop/juce_Desktop.cpp index b105bb0b95..e966164cd8 100644 --- a/modules/juce_gui_basics/desktop/juce_Desktop.cpp +++ b/modules/juce_gui_basics/desktop/juce_Desktop.cpp @@ -376,7 +376,7 @@ bool Desktop::isHeadless() const noexcept bool Desktop::supportsBorderlessNonClientResize() const { - #if JUCE_WINDOWS || JUCE_MAC + #if JUCE_MAC return true; #else return false; diff --git a/modules/juce_gui_basics/juce_gui_basics.cpp b/modules/juce_gui_basics/juce_gui_basics.cpp index b02f9bb789..912320c536 100644 --- a/modules/juce_gui_basics/juce_gui_basics.cpp +++ b/modules/juce_gui_basics/juce_gui_basics.cpp @@ -88,7 +88,6 @@ #include #include #include - #include #if JUCE_ETW_TRACELOGGING #include @@ -117,7 +116,6 @@ #pragma comment(lib, "vfw32.lib") #pragma comment(lib, "imm32.lib") #pragma comment(lib, "comctl32.lib") - #pragma comment(lib, "dwmapi.lib") #if JUCE_OPENGL #pragma comment(lib, "OpenGL32.Lib") diff --git a/modules/juce_gui_basics/native/juce_Windowing_windows.cpp b/modules/juce_gui_basics/native/juce_Windowing_windows.cpp index 77d59816f5..fd353b0d8a 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_windows.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_windows.cpp @@ -1460,6 +1460,7 @@ struct RenderContext virtual bool getResizing() const = 0; virtual void handleNcCalcSize (WPARAM wParam, LPARAM lParam) = 0; virtual void handleShowWindow() = 0; + virtual std::optional getNcHitTestResult() = 0; /* Gets a snapshot of whatever the render context is currently showing. */ virtual Image createSnapshot() = 0; @@ -1579,56 +1580,17 @@ public: handlePaintMessage(); } - std::optional> getCustomBorderSize() const - { - if (hasTitleBar() || (styleFlags & windowAppearsOnTaskbar) == 0) - return {}; - - ScopedThreadDPIAwarenessSetter setter { hwnd }; - // Apply standard padding to the left, right, and bottom of the client area. - // The system will use this for the resizable border area. - // No padding at the top, though, because we want to paint our own title there. - const auto dpi = GetDpiForWindow (hwnd); - const auto frameX = GetSystemMetricsForDpi (SM_CXFRAME, dpi); - const auto frameY = GetSystemMetricsForDpi (SM_CYFRAME, dpi); - const auto padding = GetSystemMetricsForDpi (SM_CXPADDEDBORDER, dpi); - - // On Windows 11, the non-client area drawing will obscure the top pixel of the client - // area. Adding a bit of extra padding ensures that the entirety of the client area remains - // visible. - // Unfortunately, earlier Windows versions seem to display the full title bar if the top - // padding is not zero, so we have to use a different padding value there. - const auto topPadding = SystemStats::getOperatingSystemType() == SystemStats::Windows11 - ? (int) dpi / USER_DEFAULT_SCREEN_DPI - : 0; - - return BorderSize { isFullScreen() ? frameY + padding : topPadding, - frameX + padding, - frameY + padding, - frameX + padding }; - } - - BorderSize findPhysicalBorderSize() const - { - if (const auto custom = getCustomBorderSize()) - return *custom; - - ScopedThreadDPIAwarenessSetter setter { hwnd }; - - WINDOWINFO info{}; - info.cbSize = sizeof (info); - - if (! GetWindowInfo (hwnd, &info)) - return {}; - - return { roundToInt ((info.rcClient.top - info.rcWindow.top)), - roundToInt ((info.rcClient.left - info.rcWindow.left)), - roundToInt ((info.rcWindow.bottom - info.rcClient.bottom)), - roundToInt ((info.rcWindow.right - info.rcClient.right)) }; - } - void updateBorderSize() { + WINDOWINFO info; + info.cbSize = sizeof (info); + + if (GetWindowInfo (hwnd, &info)) + windowBorder = BorderSize (roundToInt ((info.rcClient.top - info.rcWindow.top) / scaleFactor), + roundToInt ((info.rcClient.left - info.rcWindow.left) / scaleFactor), + roundToInt ((info.rcWindow.bottom - info.rcClient.bottom) / scaleFactor), + roundToInt ((info.rcWindow.right - info.rcClient.right) / scaleFactor)); + if (renderContext != nullptr) renderContext->updateBorderSize(); } @@ -1653,20 +1615,7 @@ public: fullScreen = isNowFullScreen; - const auto borderSize = findPhysicalBorderSize(); - auto newBounds = borderSize.addedTo ([&] - { - ScopedThreadDPIAwarenessSetter setter { hwnd }; - - if (! isPerMonitorDPIAwareWindow (hwnd)) - return bounds; - - if (inDpiChange) - return convertLogicalScreenRectangleToPhysical (bounds, hwnd); - - return convertLogicalScreenRectangleToPhysical (bounds, hwnd) - .withPosition (Desktop::getInstance().getDisplays().logicalToPhysical (bounds.getTopLeft())); - }()); + auto newBounds = windowBorder.addedTo (bounds); if (isNotOpaque()) { @@ -1677,29 +1626,17 @@ public: } } - const auto oldBounds = [this] - { - ScopedThreadDPIAwarenessSetter setter { hwnd }; - RECT result; - GetWindowRect (hwnd, &result); - return D2DUtilities::toRectangle (result); - }(); + auto oldBounds = getBounds(); const bool hasMoved = (oldBounds.getPosition() != bounds.getPosition()); const bool hasResized = (oldBounds.getWidth() != bounds.getWidth() || oldBounds.getHeight() != bounds.getHeight()); - DWORD flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED; + DWORD flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER; if (! hasMoved) flags |= SWP_NOMOVE; if (! hasResized) flags |= SWP_NOSIZE; - SetWindowPos (hwnd, - nullptr, - newBounds.getX(), - newBounds.getY(), - newBounds.getWidth(), - newBounds.getHeight(), - flags); + setWindowPos (hwnd, newBounds, flags, ! inDpiChange); if (hasResized && isValidPeer (this)) { @@ -1710,20 +1647,28 @@ public: Rectangle getBounds() const override { - if (parentToAddTo == nullptr) - return convertPhysicalScreenRectangleToLogical (findPhysicalBorderSize().subtractedFrom (D2DUtilities::toRectangle (getWindowScreenRect (hwnd))), hwnd); + auto bounds = [this] + { + if (parentToAddTo == nullptr) + return convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (hwnd)), hwnd); - auto localBounds = D2DUtilities::toRectangle (getWindowClientRect (hwnd)); + auto localBounds = D2DUtilities::toRectangle (getWindowClientRect (hwnd)); - if (isPerMonitorDPIAwareWindow (hwnd)) - return (localBounds.toDouble() / getPlatformScaleFactor()).toNearestInt(); + if (isPerMonitorDPIAwareWindow (hwnd)) + return (localBounds.toDouble() / getPlatformScaleFactor()).toNearestInt(); - return localBounds; + return localBounds; + }(); + + return windowBorder.subtractedFrom (bounds); } Point getScreenPosition() const { - return convertPhysicalScreenRectangleToLogical (findPhysicalBorderSize().subtractedFrom (D2DUtilities::toRectangle (getWindowScreenRect (hwnd))), hwnd).getPosition(); + auto r = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (hwnd)), hwnd); + + return { r.getX() + windowBorder.getLeft(), + r.getY() + windowBorder.getTop() }; } Point localToGlobal (Point relativePosition) override { return relativePosition + getScreenPosition().toFloat(); } @@ -1793,14 +1738,18 @@ public: { auto boundsCopy = lastNonFullscreenBounds; - ShowWindow (hwnd, SW_SHOWNORMAL); + if (hasTitleBar()) + ShowWindow (hwnd, SW_SHOWNORMAL); if (! boundsCopy.isEmpty()) setBounds (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, boundsCopy), false); } else { - ShowWindow (hwnd, SW_SHOWMAXIMIZED); + if (hasTitleBar()) + ShowWindow (hwnd, SW_SHOWMAXIMIZED); + else + SendMessageW (hwnd, WM_SETTINGCHANGE, 0, 0); } if (deletionChecker != nullptr) @@ -1816,6 +1765,9 @@ public: bool isFullScreen() const override { + if (! hasTitleBar()) + return fullScreen; + WINDOWPLACEMENT wp; wp.length = sizeof (wp); GetWindowPlacement (hwnd, &wp); @@ -1838,12 +1790,12 @@ public: OptionalBorderSize getFrameSizeIfPresent() const override { - return ComponentPeer::OptionalBorderSize { getFrameSize() }; + return ComponentPeer::OptionalBorderSize { windowBorder }; } BorderSize getFrameSize() const override { - return findPhysicalBorderSize().multipliedBy (1.0 / scaleFactor); + return windowBorder; } bool setAlwaysOnTop (bool alwaysOnTop) override @@ -2289,6 +2241,7 @@ private: ULONGLONG lastMagnifySize = 0; bool fullScreen = false, isDragging = false, isMouseOver = false, hasCreatedCaret = false, constrainerIsResizing = false; + BorderSize windowBorder; IconConverters::IconPtr currentWindowIcon; FileDropTarget* dropTarget = nullptr; UWPUIViewSettings uwpViewSettings; @@ -2449,33 +2402,33 @@ private: { type |= WS_OVERLAPPED; - if ((styleFlags & windowHasCloseButton) == 0) + if ((styleFlags & windowHasCloseButton) != 0) + { + type |= WS_SYSMENU; + } + else { // annoyingly, windows won't let you have a min/max button without a close button jassert ((styleFlags & (windowHasMinimiseButton | windowHasMaximiseButton)) == 0); } + + if ((styleFlags & windowIsResizable) != 0) + type |= WS_THICKFRAME; } else if (parentToAddTo != nullptr) { type |= WS_CHILD; } - - if (parentToAddTo == nullptr) + else { - if ((styleFlags & windowAppearsOnTaskbar) != 0) - { - exstyle |= WS_EX_APPWINDOW; - } - else - { - exstyle |= WS_EX_TOOLWINDOW; - type |= WS_POPUP; // Note that popup windows don't get rounded corners by default - } - - if ((styleFlags & windowIsResizable) != 0) - type |= WS_THICKFRAME | WS_SYSMENU; + type |= WS_POPUP | WS_SYSMENU; } + if ((styleFlags & windowAppearsOnTaskbar) == 0) + exstyle |= WS_EX_TOOLWINDOW; + else + exstyle |= WS_EX_APPWINDOW; + // Don't set WS_EX_TRANSPARENT here; setting that flag hides OpenGL child windows // behind the Direct2D composition tree. if ((styleFlags & windowHasMinimiseButton) != 0) type |= WS_MINIMIZEBOX; @@ -2486,14 +2439,6 @@ private: L"", type, 0, 0, 0, 0, parentToAddTo, nullptr, (HINSTANCE) Process::getCurrentModuleInstanceHandle(), nullptr); - if (! hasTitleBar() && parentToAddTo == nullptr) - { - // Disable rounded corners on Windows 11 for custom windows with no titlebar, - // because window borders look weird when they get rounded away. - const auto pref = DWMWCP_DONOTROUND; - DwmSetWindowAttribute (hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &pref, sizeof (pref)); - } - #if JUCE_DEBUG // The DPI-awareness context of this window and JUCE's hidden message window are different. // You normally want these to match otherwise timer events and async messages will happen @@ -2608,10 +2553,8 @@ private: void updateShadower() { - if (! component.isCurrentlyModal() - && (styleFlags & windowHasDropShadow) != 0 - && (styleFlags & windowIsTemporary) != 0 - && (! hasTitleBar() || SystemStats::getOperatingSystemType() < SystemStats::WinVista)) + if (! component.isCurrentlyModal() && (styleFlags & windowHasDropShadow) != 0 + && ((! hasTitleBar()) || SystemStats::getOperatingSystemType() < SystemStats::WinVista)) { shadower = component.getLookAndFeel().createDropShadowerForComponent (component); @@ -2693,13 +2636,7 @@ private: return false; } - enum class WindowArea - { - nonclient, - client, - }; - - void doMouseMove (Point position, bool isMouseDownEvent, WindowArea area) + void doMouseMove (Point position, bool isMouseDownEvent) { ModifierKeys modsToSend (ModifierKeys::currentModifiers); @@ -2733,8 +2670,7 @@ private: if (! TrackMouseEvent (&tme)) jassertfalse; - if (area == WindowArea::client) - Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); + Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate(); } else if (! isDragging) { @@ -2757,7 +2693,7 @@ private: } } - void doMouseDown (Point position, const WPARAM wParam, WindowArea area) + void doMouseDown (Point position, const WPARAM wParam) { // this will be handled by WM_TOUCH if (isTouchEvent() || areOtherTouchSourcesActive()) @@ -2766,7 +2702,7 @@ private: if (GetCapture() != hwnd) SetCapture (hwnd); - doMouseMove (position, true, area); + doMouseMove (position, true); if (isValidPeer (this)) { @@ -3322,51 +3258,32 @@ private: bool isConstrainedNativeWindow() const { return constrainer != nullptr - && (styleFlags & windowIsResizable) != 0 + && (styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable) && ! isKioskMode(); } Rectangle getCurrentScaledBounds() const { - const auto windowBorder = findPhysicalBorderSize().multipliedBy (1.0 / scaleFactor); - const auto unscaled = windowBorder.addedTo (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, component.getBounds())); - return detail::ScalingHelpers::unscaledScreenPosToScaled (component, unscaled); + return detail::ScalingHelpers::unscaledScreenPosToScaled (component, windowBorder.addedTo (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, component.getBounds()))); } LRESULT handleSizeConstraining (RECT& r, const WPARAM wParam) { if (isConstrainedNativeWindow()) { - const auto movingTop = wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT; - const auto movingLeft = wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT; - const auto movingBottom = wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT; - const auto movingRight = wParam == WMSZ_RIGHT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_BOTTOMRIGHT; + const auto logicalBounds = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (r).toFloat(), hwnd); + auto pos = detail::ScalingHelpers::unscaledScreenPosToScaled (component, logicalBounds).toNearestInt(); - const auto snap = [&] (auto original, auto constrained) - { - const auto snappedX = movingLeft ? constrained.withRightX (original.getRight()) : constrained.withX (original.getX()); - const auto snappedY = movingTop ? snappedX .withBottomY (original.getBottom()) : snappedX .withY (original.getY()); - return snappedY; - }; + const auto original = getCurrentScaledBounds(); - const auto physicalBounds = D2DUtilities::toRectangle (r); - const auto logicalBounds = convertPhysicalScreenRectangleToLogical (physicalBounds.toFloat(), hwnd); - const auto posFloat = detail::ScalingHelpers::unscaledScreenPosToScaled (component, logicalBounds); - auto pos = posFloat.toNearestInt(); - - constrainer->checkBounds (pos, - getCurrentScaledBounds(), + constrainer->checkBounds (pos, original, Desktop::getInstance().getDisplays().getTotalBounds (true), - movingTop, - movingLeft, - movingBottom, - movingRight); + wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT, + wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT, + wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT, + wParam == WMSZ_RIGHT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_BOTTOMRIGHT); - const auto snappedLogicalPos = snap (posFloat, pos.toFloat()); - const auto newPhysicalRect = convertLogicalScreenRectangleToPhysical (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, snappedLogicalPos).toNearestInt(), hwnd); - const auto snappedPhysicalPos = snap (physicalBounds, newPhysicalRect); - - r = D2DUtilities::toRECT (snappedPhysicalPos); + r = D2DUtilities::toRECT (convertLogicalScreenRectangleToPhysical (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, pos.toFloat()).toNearestInt(), hwnd)); } updateBorderSize(); @@ -3551,29 +3468,29 @@ private: void handleLeftClickInNCArea (WPARAM wParam) { - if (sendInputAttemptWhenModalMessage()) - return; - - switch (wParam) + if (! sendInputAttemptWhenModalMessage()) { - case HTBOTTOM: - case HTBOTTOMLEFT: - case HTBOTTOMRIGHT: - case HTGROWBOX: - case HTLEFT: - case HTRIGHT: - case HTTOP: - case HTTOPLEFT: - case HTTOPRIGHT: - if (isConstrainedNativeWindow()) + switch (wParam) { - constrainerIsResizing = true; - constrainer->resizeStart(); - } - return; + case HTBOTTOM: + case HTBOTTOMLEFT: + case HTBOTTOMRIGHT: + case HTGROWBOX: + case HTLEFT: + case HTRIGHT: + case HTTOP: + case HTTOPLEFT: + case HTTOPRIGHT: + if (isConstrainedNativeWindow()) + { + constrainerIsResizing = true; + constrainer->resizeStart(); + } + break; - default: - break; + default: + break; + } } } @@ -3651,12 +3568,6 @@ private: return { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) }; } - Point getLocalPointFromScreenLParam (LPARAM lParam) - { - const auto globalPos = D2DUtilities::toPoint (getPOINTFromLParam (lParam)); - return globalToLocal (convertPhysicalScreenPointToLogical (globalPos, hwnd).toFloat()); - } - Point getPointFromLocalLParam (LPARAM lParam) noexcept { auto p = D2DUtilities::toPoint (getPOINTFromLParam (lParam)); @@ -3666,9 +3577,8 @@ private: // LPARAM is relative to this window's top-left but may be on a different monitor so we need to calculate the // physical screen position and then convert this to local logical coordinates auto r = getWindowScreenRect (hwnd); - const auto windowBorder = findPhysicalBorderSize(); - return globalToLocal (Desktop::getInstance().getDisplays().physicalToLogical (D2DUtilities::toPoint ({ r.left + p.x + windowBorder.getLeft(), - r.top + p.y + windowBorder.getTop() })).toFloat()); + return globalToLocal (Desktop::getInstance().getDisplays().physicalToLogical (D2DUtilities::toPoint ({ r.left + p.x + roundToInt (windowBorder.getLeft() * scaleFactor), + r.top + p.y + roundToInt (windowBorder.getTop() * scaleFactor) })).toFloat()); } return p.toFloat(); @@ -3685,41 +3595,14 @@ private: { //============================================================================== case WM_NCHITTEST: - { if ((styleFlags & windowIgnoresMouseClicks) != 0) return HTTRANSPARENT; - if (! hasTitleBar() && parentToAddTo == nullptr) - { - if ((styleFlags & windowIsResizable) != 0) - if (const auto result = DefWindowProc (h, message, wParam, lParam); HTSIZEFIRST <= result && result <= HTSIZELAST) - return result; - - const auto kind = component.findControlAtPoint (getLocalPointFromScreenLParam (lParam).toFloat()); - - using Kind = Component::WindowControlKind; - switch (kind) - { - case Kind::client: return HTCLIENT; - case Kind::caption: return HTCAPTION; - case Kind::minimise: return HTMINBUTTON; - case Kind::maximise: return HTMAXBUTTON; - case Kind::close: return HTCLOSE; - case Kind::sizeTop: return HTTOP; - case Kind::sizeLeft: return HTLEFT; - case Kind::sizeRight: return HTRIGHT; - case Kind::sizeBottom: return HTBOTTOM; - case Kind::sizeTopLeft: return HTTOPLEFT; - case Kind::sizeTopRight: return HTTOPRIGHT; - case Kind::sizeBottomLeft: return HTBOTTOMLEFT; - case Kind::sizeBottomRight: return HTBOTTOMRIGHT; - } - - return HTNOWHERE; - } + if (renderContext != nullptr) + if (auto result = renderContext->getNcHitTestResult()) + return *result; break; - } //============================================================================== case WM_PAINT: @@ -3727,11 +3610,12 @@ private: return 0; case WM_NCPAINT: - // this must be done, even with native titlebars, or there are rendering artifacts. - handlePaintMessage(); - // Even if we're *not* using a native titlebar (i.e. extending into the nonclient area) - // the system needs to handle the NCPAINT to draw rounded corners and shadows. - break; + handlePaintMessage(); // this must be done, even with native titlebars, or there are rendering artifacts. + + if (hasTitleBar()) + break; // let the DefWindowProc handle drawing the frame. + + return 0; case WM_ERASEBKGND: if (hasTitleBar()) @@ -3740,27 +3624,10 @@ private: return 1; case WM_NCCALCSIZE: - { if (renderContext != nullptr) renderContext->handleNcCalcSize (wParam, lParam); - if (! wParam) - break; - - const auto custom = getCustomBorderSize(); - - if (! custom.has_value()) - break; - - auto& rect = *reinterpret_cast (lParam)->rgrc; - - rect.top += custom->getTop(); - rect.bottom -= custom->getBottom(); - rect.left += custom->getLeft(); - rect.right -= custom->getRight(); - - return 0; - } + break; //============================================================================== case WM_POINTERUPDATE: @@ -3779,21 +3646,14 @@ private: break; //============================================================================== - case WM_NCMOUSEMOVE: - case WM_MOUSEMOVE: - doMouseMove (message == WM_MOUSEMOVE ? getPointFromLocalLParam (lParam) : getLocalPointFromScreenLParam (lParam), - false, - message == WM_MOUSEMOVE ? WindowArea::client : WindowArea::nonclient); - return 0; + case WM_MOUSEMOVE: doMouseMove (getPointFromLocalLParam (lParam), false); return 0; case WM_POINTERLEAVE: case WM_MOUSELEAVE: doMouseExit(); return 0; case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - doMouseDown (getPointFromLocalLParam (lParam), wParam, WindowArea::client); - return 0; + case WM_RBUTTONDOWN: doMouseDown (getPointFromLocalLParam (lParam), wParam); return 0; case WM_LBUTTONUP: case WM_MBUTTONUP: @@ -3807,6 +3667,13 @@ private: case WM_CAPTURECHANGED: doCaptureChanged(); return 0; + case WM_NCPOINTERUPDATE: + case WM_NCMOUSEMOVE: + if (hasTitleBar()) + break; + + return 0; + case WM_TOUCH: if (getTouchInputInfo != nullptr) return doTouchEvent ((int) wParam, (HTOUCHINPUT) lParam); @@ -4011,8 +3878,12 @@ private: if (sendInputAttemptWhenModalMessage()) return 0; - PostMessage (h, WM_CLOSE, 0, 0); - return 0; + if (hasTitleBar()) + { + PostMessage (h, WM_CLOSE, 0, 0); + return 0; + } + break; case SC_KEYMENU: #if ! JUCE_WINDOWS_ALT_KEY_TRIGGERS_MENU @@ -4027,24 +3898,27 @@ private: // (NB mustn't call sendInputAttemptWhenModalMessage() here because of very obscure // situations that can arise if a modal loop is started from an alt-key keypress). - if (h == GetCapture()) + if (hasTitleBar() && h == GetCapture()) ReleaseCapture(); break; case SC_MAXIMIZE: - if (sendInputAttemptWhenModalMessage()) - return 0; + if (! sendInputAttemptWhenModalMessage()) + setFullScreen (true); - setFullScreen (true); return 0; case SC_MINIMIZE: if (sendInputAttemptWhenModalMessage()) return 0; - setMinimised (true); - return 0; + if (! hasTitleBar()) + { + setMinimised (true); + return 0; + } + break; case SC_RESTORE: if (sendInputAttemptWhenModalMessage()) @@ -4073,38 +3947,14 @@ private: break; case WM_NCPOINTERDOWN: - handleLeftClickInNCArea (HIWORD (wParam)); - break; - case WM_NCLBUTTONDOWN: handleLeftClickInNCArea (wParam); - - if (wParam == HTCLOSE || wParam == HTMAXBUTTON || wParam == HTMINBUTTON) - return 0; - - break; - - case WM_NCLBUTTONUP: - switch (wParam) - { - case HTCLOSE: - PostMessage (h, WM_CLOSE, 0, 0); - return 0; - - case HTMAXBUTTON: - setFullScreen (! isFullScreen()); - return 0; - - case HTMINBUTTON: - setMinimised (true); - return 0; - } break; case WM_NCRBUTTONDOWN: case WM_NCMBUTTONDOWN: sendInputAttemptWhenModalMessage(); - return 0; + break; case WM_IME_SETCONTEXT: imeHandler.handleSetContext (h, wParam == TRUE); @@ -4140,7 +3990,7 @@ private: break; } - return DefWindowProc (h, message, wParam, lParam); + return DefWindowProcW (h, message, wParam, lParam); } bool sendInputAttemptWhenModalMessage() @@ -4622,6 +4472,15 @@ public: void setResizing (bool x) override { resizing = x; } bool getResizing() const override { return resizing; } + + std::optional getNcHitTestResult() override + { + if (! peer.hasTitleBar()) + return HTCLIENT; + + return {}; + } + void handleNcCalcSize (WPARAM, LPARAM) override {} void handleShowWindow() override {} @@ -4878,6 +4737,8 @@ public: handleDirect2DPaint(); } + std::optional getNcHitTestResult() override { return {}; } + void setResizing (bool x) override { direct2DContext->setResizing (x);