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:
parent
f8d38edcd4
commit
a8fa44e05c
8 changed files with 115 additions and 3 deletions
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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"; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue