mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Reapply "Windows: Use new window hit-testing API to implement Windows window-management features like Aero Snap"
This reverts commit 086e2264895fa40059c451603abd491fb41f4558.
This commit is contained in:
parent
01cacf2958
commit
467f20a7a1
3 changed files with 284 additions and 142 deletions
|
|
@ -376,7 +376,7 @@ bool Desktop::isHeadless() const noexcept
|
|||
|
||||
bool Desktop::supportsBorderlessNonClientResize() const
|
||||
{
|
||||
#if JUCE_MAC
|
||||
#if JUCE_WINDOWS || JUCE_MAC
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
#include <sapi.h>
|
||||
#include <vfw.h>
|
||||
#include <windowsx.h>
|
||||
#include <dwmapi.h>
|
||||
|
||||
#if JUCE_ETW_TRACELOGGING
|
||||
#include <TraceLoggingProvider.h>
|
||||
|
|
@ -107,6 +108,7 @@
|
|||
#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")
|
||||
|
|
|
|||
|
|
@ -1456,7 +1456,6 @@ struct RenderContext
|
|||
virtual bool getResizing() const = 0;
|
||||
virtual void handleNcCalcSize (WPARAM wParam, LPARAM lParam) = 0;
|
||||
virtual void handleShowWindow() = 0;
|
||||
virtual std::optional<LRESULT> getNcHitTestResult() = 0;
|
||||
|
||||
/* Gets a snapshot of whatever the render context is currently showing. */
|
||||
virtual Image createSnapshot() = 0;
|
||||
|
|
@ -1576,17 +1575,56 @@ public:
|
|||
handlePaintMessage();
|
||||
}
|
||||
|
||||
void updateBorderSize()
|
||||
std::optional<BorderSize<int>> getCustomBorderSize() const
|
||||
{
|
||||
WINDOWINFO info;
|
||||
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<int> { isFullScreen() ? frameY + padding : topPadding,
|
||||
frameX + padding,
|
||||
frameY + padding,
|
||||
frameX + padding };
|
||||
}
|
||||
|
||||
BorderSize<int> findPhysicalBorderSize() const
|
||||
{
|
||||
if (const auto custom = getCustomBorderSize())
|
||||
return *custom;
|
||||
|
||||
ScopedThreadDPIAwarenessSetter setter { hwnd };
|
||||
|
||||
WINDOWINFO info{};
|
||||
info.cbSize = sizeof (info);
|
||||
|
||||
if (GetWindowInfo (hwnd, &info))
|
||||
windowBorder = BorderSize<int> (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 (! 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()
|
||||
{
|
||||
if (renderContext != nullptr)
|
||||
renderContext->updateBorderSize();
|
||||
}
|
||||
|
|
@ -1611,7 +1649,20 @@ public:
|
|||
|
||||
fullScreen = isNowFullScreen;
|
||||
|
||||
auto newBounds = windowBorder.addedTo (bounds);
|
||||
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()));
|
||||
}());
|
||||
|
||||
if (isNotOpaque())
|
||||
{
|
||||
|
|
@ -1622,17 +1673,29 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
auto oldBounds = getBounds();
|
||||
const auto oldBounds = [this]
|
||||
{
|
||||
ScopedThreadDPIAwarenessSetter setter { hwnd };
|
||||
RECT result;
|
||||
GetWindowRect (hwnd, &result);
|
||||
return D2DUtilities::toRectangle (result);
|
||||
}();
|
||||
|
||||
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;
|
||||
DWORD flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED;
|
||||
if (! hasMoved) flags |= SWP_NOMOVE;
|
||||
if (! hasResized) flags |= SWP_NOSIZE;
|
||||
|
||||
setWindowPos (hwnd, newBounds, flags, ! inDpiChange);
|
||||
SetWindowPos (hwnd,
|
||||
nullptr,
|
||||
newBounds.getX(),
|
||||
newBounds.getY(),
|
||||
newBounds.getWidth(),
|
||||
newBounds.getHeight(),
|
||||
flags);
|
||||
|
||||
if (hasResized && isValidPeer (this))
|
||||
{
|
||||
|
|
@ -1642,11 +1705,9 @@ public:
|
|||
}
|
||||
|
||||
Rectangle<int> getBounds() const override
|
||||
{
|
||||
auto bounds = [this]
|
||||
{
|
||||
if (parentToAddTo == nullptr)
|
||||
return convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (hwnd)), hwnd);
|
||||
return convertPhysicalScreenRectangleToLogical (findPhysicalBorderSize().subtractedFrom (D2DUtilities::toRectangle (getWindowScreenRect (hwnd))), hwnd);
|
||||
|
||||
auto localBounds = D2DUtilities::toRectangle (getWindowClientRect (hwnd));
|
||||
|
||||
|
|
@ -1654,17 +1715,11 @@ public:
|
|||
return (localBounds.toDouble() / getPlatformScaleFactor()).toNearestInt();
|
||||
|
||||
return localBounds;
|
||||
}();
|
||||
|
||||
return windowBorder.subtractedFrom (bounds);
|
||||
}
|
||||
|
||||
Point<int> getScreenPosition() const
|
||||
{
|
||||
auto r = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (hwnd)), hwnd);
|
||||
|
||||
return { r.getX() + windowBorder.getLeft(),
|
||||
r.getY() + windowBorder.getTop() };
|
||||
return convertPhysicalScreenRectangleToLogical (findPhysicalBorderSize().subtractedFrom (D2DUtilities::toRectangle (getWindowScreenRect (hwnd))), hwnd).getPosition();
|
||||
}
|
||||
|
||||
Point<float> localToGlobal (Point<float> relativePosition) override { return relativePosition + getScreenPosition().toFloat(); }
|
||||
|
|
@ -1734,7 +1789,6 @@ public:
|
|||
{
|
||||
auto boundsCopy = lastNonFullscreenBounds;
|
||||
|
||||
if (hasTitleBar())
|
||||
ShowWindow (hwnd, SW_SHOWNORMAL);
|
||||
|
||||
if (! boundsCopy.isEmpty())
|
||||
|
|
@ -1742,10 +1796,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
if (hasTitleBar())
|
||||
ShowWindow (hwnd, SW_SHOWMAXIMIZED);
|
||||
else
|
||||
SendMessageW (hwnd, WM_SETTINGCHANGE, 0, 0);
|
||||
}
|
||||
|
||||
if (deletionChecker != nullptr)
|
||||
|
|
@ -1761,9 +1812,6 @@ public:
|
|||
|
||||
bool isFullScreen() const override
|
||||
{
|
||||
if (! hasTitleBar())
|
||||
return fullScreen;
|
||||
|
||||
WINDOWPLACEMENT wp;
|
||||
wp.length = sizeof (wp);
|
||||
GetWindowPlacement (hwnd, &wp);
|
||||
|
|
@ -1800,12 +1848,12 @@ public:
|
|||
|
||||
OptionalBorderSize getFrameSizeIfPresent() const override
|
||||
{
|
||||
return ComponentPeer::OptionalBorderSize { windowBorder };
|
||||
return ComponentPeer::OptionalBorderSize { getFrameSize() };
|
||||
}
|
||||
|
||||
BorderSize<int> getFrameSize() const override
|
||||
{
|
||||
return windowBorder;
|
||||
return findPhysicalBorderSize().multipliedBy (1.0 / scaleFactor);
|
||||
}
|
||||
|
||||
bool setAlwaysOnTop (bool alwaysOnTop) override
|
||||
|
|
@ -2251,7 +2299,6 @@ private:
|
|||
ULONGLONG lastMagnifySize = 0;
|
||||
bool fullScreen = false, isDragging = false, isMouseOver = false,
|
||||
hasCreatedCaret = false, constrainerIsResizing = false;
|
||||
BorderSize<int> windowBorder;
|
||||
IconConverters::IconPtr currentWindowIcon;
|
||||
FileDropTarget* dropTarget = nullptr;
|
||||
UWPUIViewSettings uwpViewSettings;
|
||||
|
|
@ -2412,32 +2459,32 @@ private:
|
|||
{
|
||||
type |= WS_OVERLAPPED;
|
||||
|
||||
if ((styleFlags & windowHasCloseButton) != 0)
|
||||
{
|
||||
type |= WS_SYSMENU;
|
||||
}
|
||||
else
|
||||
if ((styleFlags & windowHasCloseButton) == 0)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
if ((styleFlags & windowAppearsOnTaskbar) != 0)
|
||||
{
|
||||
exstyle |= WS_EX_APPWINDOW;
|
||||
}
|
||||
else
|
||||
{
|
||||
type |= WS_POPUP | WS_SYSMENU;
|
||||
exstyle |= WS_EX_TOOLWINDOW;
|
||||
type |= WS_POPUP; // Note that popup windows don't get rounded corners by default
|
||||
}
|
||||
|
||||
if ((styleFlags & windowAppearsOnTaskbar) == 0)
|
||||
exstyle |= WS_EX_TOOLWINDOW;
|
||||
else
|
||||
exstyle |= WS_EX_APPWINDOW;
|
||||
if ((styleFlags & windowIsResizable) != 0)
|
||||
type |= WS_THICKFRAME | WS_SYSMENU;
|
||||
}
|
||||
|
||||
// Don't set WS_EX_TRANSPARENT here; setting that flag hides OpenGL child windows
|
||||
// behind the Direct2D composition tree.
|
||||
|
|
@ -2449,6 +2496,14 @@ 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
|
||||
|
|
@ -2563,7 +2618,10 @@ private:
|
|||
|
||||
void updateShadower()
|
||||
{
|
||||
if (! component.isCurrentlyModal() && (styleFlags & windowHasDropShadow) != 0 && ! hasTitleBar())
|
||||
if (! component.isCurrentlyModal()
|
||||
&& (styleFlags & windowHasDropShadow) != 0
|
||||
&& (styleFlags & windowIsTemporary) != 0
|
||||
&& ! hasTitleBar())
|
||||
{
|
||||
shadower = component.getLookAndFeel().createDropShadowerForComponent (component);
|
||||
|
||||
|
|
@ -2637,7 +2695,13 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
void doMouseMove (Point<float> position, bool isMouseDownEvent)
|
||||
enum class WindowArea
|
||||
{
|
||||
nonclient,
|
||||
client,
|
||||
};
|
||||
|
||||
void doMouseMove (Point<float> position, bool isMouseDownEvent, WindowArea area)
|
||||
{
|
||||
ModifierKeys modsToSend (ModifierKeys::currentModifiers);
|
||||
|
||||
|
|
@ -2671,6 +2735,7 @@ private:
|
|||
if (! TrackMouseEvent (&tme))
|
||||
jassertfalse;
|
||||
|
||||
if (area == WindowArea::client)
|
||||
Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
|
||||
}
|
||||
else if (! isDragging)
|
||||
|
|
@ -2693,7 +2758,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void doMouseDown (Point<float> position, const WPARAM wParam)
|
||||
void doMouseDown (Point<float> position, const WPARAM wParam, WindowArea area)
|
||||
{
|
||||
// this will be handled by WM_TOUCH
|
||||
if (isTouchEvent() || areOtherTouchSourcesActive())
|
||||
|
|
@ -2702,7 +2767,7 @@ private:
|
|||
if (GetCapture() != hwnd)
|
||||
SetCapture (hwnd);
|
||||
|
||||
doMouseMove (position, true);
|
||||
doMouseMove (position, true, area);
|
||||
|
||||
if (isValidPeer (this))
|
||||
{
|
||||
|
|
@ -3258,32 +3323,51 @@ private:
|
|||
bool isConstrainedNativeWindow() const
|
||||
{
|
||||
return constrainer != nullptr
|
||||
&& (styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable)
|
||||
&& (styleFlags & windowIsResizable) != 0
|
||||
&& ! isKioskMode();
|
||||
}
|
||||
|
||||
Rectangle<int> getCurrentScaledBounds() const
|
||||
{
|
||||
return detail::ScalingHelpers::unscaledScreenPosToScaled (component, windowBorder.addedTo (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, component.getBounds())));
|
||||
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);
|
||||
}
|
||||
|
||||
LRESULT handleSizeConstraining (RECT& r, const WPARAM wParam)
|
||||
{
|
||||
if (isConstrainedNativeWindow())
|
||||
{
|
||||
const auto logicalBounds = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (r).toFloat(), hwnd);
|
||||
auto pos = detail::ScalingHelpers::unscaledScreenPosToScaled (component, logicalBounds).toNearestInt();
|
||||
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 original = getCurrentScaledBounds();
|
||||
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;
|
||||
};
|
||||
|
||||
constrainer->checkBounds (pos, original,
|
||||
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(),
|
||||
Desktop::getInstance().getDisplays().getTotalBounds (true),
|
||||
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);
|
||||
movingTop,
|
||||
movingLeft,
|
||||
movingBottom,
|
||||
movingRight);
|
||||
|
||||
r = D2DUtilities::toRECT (convertLogicalScreenRectangleToPhysical (detail::ScalingHelpers::scaledScreenPosToUnscaled (component, pos.toFloat()).toNearestInt(), hwnd));
|
||||
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);
|
||||
}
|
||||
|
||||
updateBorderSize();
|
||||
|
|
@ -3468,8 +3552,9 @@ private:
|
|||
|
||||
void handleLeftClickInNCArea (WPARAM wParam)
|
||||
{
|
||||
if (! sendInputAttemptWhenModalMessage())
|
||||
{
|
||||
if (sendInputAttemptWhenModalMessage())
|
||||
return;
|
||||
|
||||
switch (wParam)
|
||||
{
|
||||
case HTBOTTOM:
|
||||
|
|
@ -3486,13 +3571,12 @@ private:
|
|||
constrainerIsResizing = true;
|
||||
constrainer->resizeStart();
|
||||
}
|
||||
break;
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initialiseSysMenu (HMENU menu) const
|
||||
{
|
||||
|
|
@ -3568,6 +3652,12 @@ private:
|
|||
return { GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam) };
|
||||
}
|
||||
|
||||
Point<float> getLocalPointFromScreenLParam (LPARAM lParam)
|
||||
{
|
||||
const auto globalPos = D2DUtilities::toPoint (getPOINTFromLParam (lParam));
|
||||
return globalToLocal (convertPhysicalScreenPointToLogical (globalPos, hwnd).toFloat());
|
||||
}
|
||||
|
||||
Point<float> getPointFromLocalLParam (LPARAM lParam) noexcept
|
||||
{
|
||||
auto p = D2DUtilities::toPoint (getPOINTFromLParam (lParam));
|
||||
|
|
@ -3577,8 +3667,9 @@ 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);
|
||||
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());
|
||||
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 p.toFloat();
|
||||
|
|
@ -3595,14 +3686,41 @@ private:
|
|||
{
|
||||
//==============================================================================
|
||||
case WM_NCHITTEST:
|
||||
{
|
||||
if ((styleFlags & windowIgnoresMouseClicks) != 0)
|
||||
return HTTRANSPARENT;
|
||||
|
||||
if (renderContext != nullptr)
|
||||
if (auto result = renderContext->getNcHitTestResult())
|
||||
return *result;
|
||||
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;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
case WM_PAINT:
|
||||
|
|
@ -3610,12 +3728,11 @@ private:
|
|||
return 0;
|
||||
|
||||
case WM_NCPAINT:
|
||||
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;
|
||||
// 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;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
if (hasTitleBar())
|
||||
|
|
@ -3624,11 +3741,28 @@ 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<NCCALCSIZE_PARAMS *> (lParam)->rgrc;
|
||||
|
||||
rect.top += custom->getTop();
|
||||
rect.bottom -= custom->getBottom();
|
||||
rect.left += custom->getLeft();
|
||||
rect.right -= custom->getRight();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
case WM_POINTERUPDATE:
|
||||
if (handlePointerInput (wParam, lParam, false, false))
|
||||
|
|
@ -3646,14 +3780,21 @@ private:
|
|||
break;
|
||||
|
||||
//==============================================================================
|
||||
case WM_MOUSEMOVE: doMouseMove (getPointFromLocalLParam (lParam), false); return 0;
|
||||
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_POINTERLEAVE:
|
||||
case WM_MOUSELEAVE: doMouseExit(); return 0;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN: doMouseDown (getPointFromLocalLParam (lParam), wParam); return 0;
|
||||
case WM_RBUTTONDOWN:
|
||||
doMouseDown (getPointFromLocalLParam (lParam), wParam, WindowArea::client);
|
||||
return 0;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
|
|
@ -3667,13 +3808,6 @@ 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);
|
||||
|
|
@ -3878,12 +4012,8 @@ private:
|
|||
if (sendInputAttemptWhenModalMessage())
|
||||
return 0;
|
||||
|
||||
if (hasTitleBar())
|
||||
{
|
||||
PostMessage (h, WM_CLOSE, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_KEYMENU:
|
||||
#if ! JUCE_WINDOWS_ALT_KEY_TRIGGERS_MENU
|
||||
|
|
@ -3898,27 +4028,24 @@ 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 (hasTitleBar() && h == GetCapture())
|
||||
if (h == GetCapture())
|
||||
ReleaseCapture();
|
||||
|
||||
break;
|
||||
|
||||
case SC_MAXIMIZE:
|
||||
if (! sendInputAttemptWhenModalMessage())
|
||||
setFullScreen (true);
|
||||
if (sendInputAttemptWhenModalMessage())
|
||||
return 0;
|
||||
|
||||
setFullScreen (true);
|
||||
return 0;
|
||||
|
||||
case SC_MINIMIZE:
|
||||
if (sendInputAttemptWhenModalMessage())
|
||||
return 0;
|
||||
|
||||
if (! hasTitleBar())
|
||||
{
|
||||
setMinimised (true);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_RESTORE:
|
||||
if (sendInputAttemptWhenModalMessage())
|
||||
|
|
@ -3947,14 +4074,38 @@ 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();
|
||||
break;
|
||||
return 0;
|
||||
|
||||
case WM_IME_SETCONTEXT:
|
||||
imeHandler.handleSetContext (h, wParam == TRUE);
|
||||
|
|
@ -3990,7 +4141,7 @@ private:
|
|||
break;
|
||||
}
|
||||
|
||||
return DefWindowProcW (h, message, wParam, lParam);
|
||||
return DefWindowProc (h, message, wParam, lParam);
|
||||
}
|
||||
|
||||
bool sendInputAttemptWhenModalMessage()
|
||||
|
|
@ -4472,15 +4623,6 @@ public:
|
|||
|
||||
void setResizing (bool x) override { resizing = x; }
|
||||
bool getResizing() const override { return resizing; }
|
||||
|
||||
std::optional<LRESULT> getNcHitTestResult() override
|
||||
{
|
||||
if (! peer.hasTitleBar())
|
||||
return HTCLIENT;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void handleNcCalcSize (WPARAM, LPARAM) override {}
|
||||
void handleShowWindow() override {}
|
||||
|
||||
|
|
@ -4737,8 +4879,6 @@ public:
|
|||
handleDirect2DPaint();
|
||||
}
|
||||
|
||||
std::optional<LRESULT> getNcHitTestResult() override { return {}; }
|
||||
|
||||
void setResizing (bool x) override
|
||||
{
|
||||
direct2DContext->setResizing (x);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue