1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-20 01:14:20 +00:00

X11: Ask the host to manage client-initiated resizes

This commit is contained in:
reuk 2023-07-20 18:52:10 +01:00
parent f8d38edcd4
commit a8fa44e05c
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
8 changed files with 115 additions and 3 deletions

View file

@ -125,6 +125,10 @@ void ResizableBorderComponent::mouseDown (const MouseEvent& e)
originalBounds = component->getBounds();
if (auto* peer = component->getPeer())
if (&peer->getComponent() == component)
peer->startHostManagedResize (peer->globalToLocal (localPointToGlobal (e.getPosition())), mouseZone);
if (constrainer != nullptr)
constrainer->resizeStart();
}

View file

@ -125,7 +125,7 @@ public:
/** Returns an appropriate mouse-cursor for this resize zone. */
MouseCursor getMouseCursor() const noexcept;
/** Returns true if dragging this zone will move the enire object without resizing it. */
/** Returns true if dragging this zone will move the entire object without resizing it. */
bool isDraggingWholeObject() const noexcept { return zone == centre; }
/** Returns true if dragging this zone will move the object's left edge. */
bool isDraggingLeftEdge() const noexcept { return (zone & left) != 0; }

View file

@ -45,7 +45,7 @@ void ResizableCornerComponent::paint (Graphics& g)
isMouseButtonDown());
}
void ResizableCornerComponent::mouseDown (const MouseEvent&)
void ResizableCornerComponent::mouseDown (const MouseEvent& e)
{
if (component == nullptr)
{
@ -55,6 +55,13 @@ void ResizableCornerComponent::mouseDown (const MouseEvent&)
originalBounds = component->getBounds();
using Zone = ResizableBorderComponent::Zone;
const Zone zone { Zone::bottom | Zone::right };
if (auto* peer = component->getPeer())
if (&peer->getComponent() == component)
peer->startHostManagedResize (peer->globalToLocal (localPointToGlobal (e.getPosition())), zone);
if (constrainer != nullptr)
constrainer->resizeStart();
}

View file

@ -52,7 +52,7 @@ void ResizableEdgeComponent::paint (Graphics& g)
isMouseOver(), isMouseButtonDown());
}
void ResizableEdgeComponent::mouseDown (const MouseEvent&)
void ResizableEdgeComponent::mouseDown (const MouseEvent& e)
{
if (component == nullptr)
{
@ -62,6 +62,25 @@ void ResizableEdgeComponent::mouseDown (const MouseEvent&)
originalBounds = component->getBounds();
using Zone = ResizableBorderComponent::Zone;
const Zone zone { [&]
{
switch (edge)
{
case Edge::leftEdge: return Zone::left;
case Edge::rightEdge: return Zone::right;
case Edge::topEdge: return Zone::top;
case Edge::bottomEdge: return Zone::bottom;
}
return Zone::centre;
}() };
if (auto* peer = component->getPeer())
if (&peer->getComponent() == component)
peer->startHostManagedResize (peer->globalToLocal (localPointToGlobal (e.getPosition())), zone);
if (constrainer != nullptr)
constrainer->resizeStart();
}

View file

@ -399,6 +399,12 @@ public:
void clearWindowAssociation() { association = {}; }
void startHostManagedResize (Point<int> mouseDownPosition,
ResizableBorderComponent::Zone zone) override
{
XWindowSystem::getInstance()->startHostManagedResize (windowH, mouseDownPosition, zone);
}
//==============================================================================
static bool isActiveApplication;
bool focused = false;

View file

@ -1789,6 +1789,68 @@ void XWindowSystem::setBounds (::Window windowH, Rectangle<int> newBounds, bool
}
}
void XWindowSystem::startHostManagedResize (::Window windowH,
Point<int> mouseDown,
ResizableBorderComponent::Zone zone)
{
const auto moveResize = XWindowSystemUtilities::Atoms::getIfExists (display, "_NET_WM_MOVERESIZE");
if (moveResize == None)
return;
XWindowSystemUtilities::ScopedXLock xLock;
X11Symbols::getInstance()->xUngrabPointer (display, CurrentTime);
const auto root = X11Symbols::getInstance()->xRootWindow (display, X11Symbols::getInstance()->xDefaultScreen (display));
XClientMessageEvent clientMsg;
clientMsg.display = display;
clientMsg.window = windowH;
clientMsg.type = ClientMessage;
clientMsg.format = 32;
clientMsg.message_type = moveResize;
clientMsg.data.l[0] = mouseDown.getX();
clientMsg.data.l[1] = mouseDown.getY();
clientMsg.data.l[2] = [&]
{
// It's unclear which header is supposed to contain these
static constexpr auto _NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0;
static constexpr auto _NET_WM_MOVERESIZE_SIZE_TOP = 1;
static constexpr auto _NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2;
static constexpr auto _NET_WM_MOVERESIZE_SIZE_RIGHT = 3;
static constexpr auto _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4;
static constexpr auto _NET_WM_MOVERESIZE_SIZE_BOTTOM = 5;
static constexpr auto _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6;
static constexpr auto _NET_WM_MOVERESIZE_SIZE_LEFT = 7;
static constexpr auto _NET_WM_MOVERESIZE_MOVE = 8;
using F = ResizableBorderComponent::Zone::Zones;
switch (zone.getZoneFlags())
{
case F::top | F::left: return _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
case F::top: return _NET_WM_MOVERESIZE_SIZE_TOP;
case F::top | F::right: return _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
case F::right: return _NET_WM_MOVERESIZE_SIZE_RIGHT;
case F::bottom | F::right: return _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
case F::bottom: return _NET_WM_MOVERESIZE_SIZE_BOTTOM;
case F::bottom | F::left: return _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
case F::left: return _NET_WM_MOVERESIZE_SIZE_LEFT;
}
return _NET_WM_MOVERESIZE_MOVE;
}();
clientMsg.data.l[3] = 0;
clientMsg.data.l[4] = 1;
X11Symbols::getInstance()->xSendEvent (display,
root,
false,
SubstructureRedirectMask | SubstructureNotifyMask,
unalignedPointerCast<XEvent*> (&clientMsg));
}
void XWindowSystem::updateConstraints (::Window windowH) const
{
if (auto* peer = getPeerFor (windowH))

View file

@ -241,6 +241,10 @@ public:
bool isX11Available() const noexcept { return xIsAvailable; }
void startHostManagedResize (::Window window,
Point<int> mouseDown,
ResizableBorderComponent::Zone zone);
static String getWindowScalingFactorSettingName() { return "Gdk/WindowScalingFactor"; }
static String getThemeNameSettingName() { return "Net/ThemeName"; }

View file

@ -258,6 +258,16 @@ public:
*/
void setConstrainer (ComponentBoundsConstrainer* newConstrainer) noexcept;
/** Asks the window-manager to begin resizing this window, on platforms where this is useful
(currently just Linux/X11).
@param mouseDownPosition The position of the mouse event that started the resize in
unscaled peer coordinates
@param zone The edges of the window that may be moved during the resize
*/
virtual void startHostManagedResize ([[maybe_unused]] Point<int> mouseDownPosition,
[[maybe_unused]] ResizableBorderComponent::Zone zone) {}
/** Returns the current constrainer, if one has been set. */
ComponentBoundsConstrainer* getConstrainer() const noexcept { return constrainer; }