wayland: Move unconstraining logic to XdgPositioner
This makes unconstraining code more reusable (in case of applet popups use xdg-positioner too), and in general, it makes sense for better encapsulation.
This commit is contained in:
parent
23238b175a
commit
4b6c83be12
4 changed files with 130 additions and 129 deletions
|
@ -11,6 +11,7 @@
|
||||||
#include "output_interface.h"
|
#include "output_interface.h"
|
||||||
#include "seat_interface.h"
|
#include "seat_interface.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "utils/common.h"
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
@ -1075,6 +1076,121 @@ quint32 XdgPositioner::parentConfigure() const
|
||||||
return d->parentConfigure;
|
return d->parentConfigure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRectF XdgPositioner::placement(const QRectF &bounds) const
|
||||||
|
{
|
||||||
|
// returns if a target is within the supplied bounds, optional edges argument states which side to check
|
||||||
|
auto inBounds = [bounds](const QRectF &target, Qt::Edges edges = Qt::LeftEdge | Qt::RightEdge | Qt::TopEdge | Qt::BottomEdge) -> bool {
|
||||||
|
if (edges & Qt::LeftEdge && target.left() < bounds.left()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (edges & Qt::TopEdge && target.top() < bounds.top()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (edges & Qt::RightEdge && target.right() > bounds.right()) {
|
||||||
|
// normal QRect::right issue cancels out
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (edges & Qt::BottomEdge && target.bottom() > bounds.bottom()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
QRectF popupRect(KWin::popupOffset(anchorRect(), anchorEdges(), gravityEdges(), size()) + offset(), size());
|
||||||
|
|
||||||
|
// if that fits, we don't need to do anything
|
||||||
|
if (inBounds(popupRect)) {
|
||||||
|
return popupRect;
|
||||||
|
}
|
||||||
|
// otherwise apply constraint adjustment per axis in order XDG Shell Popup states
|
||||||
|
|
||||||
|
if (flipConstraintAdjustments() & Qt::Horizontal) {
|
||||||
|
if (!inBounds(popupRect, Qt::LeftEdge | Qt::RightEdge)) {
|
||||||
|
// flip both edges (if either bit is set, XOR both)
|
||||||
|
auto flippedAnchorEdge = anchorEdges();
|
||||||
|
if (flippedAnchorEdge & (Qt::LeftEdge | Qt::RightEdge)) {
|
||||||
|
flippedAnchorEdge ^= (Qt::LeftEdge | Qt::RightEdge);
|
||||||
|
}
|
||||||
|
auto flippedGravity = gravityEdges();
|
||||||
|
if (flippedGravity & (Qt::LeftEdge | Qt::RightEdge)) {
|
||||||
|
flippedGravity ^= (Qt::LeftEdge | Qt::RightEdge);
|
||||||
|
}
|
||||||
|
auto flippedPopupRect = QRectF(KWin::popupOffset(anchorRect(), flippedAnchorEdge, flippedGravity, size()) + offset(), size());
|
||||||
|
|
||||||
|
// if it still doesn't fit we should continue with the unflipped version
|
||||||
|
if (inBounds(flippedPopupRect, Qt::LeftEdge | Qt::RightEdge)) {
|
||||||
|
popupRect.moveLeft(flippedPopupRect.left());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slideConstraintAdjustments() & Qt::Horizontal) {
|
||||||
|
if (!inBounds(popupRect, Qt::LeftEdge)) {
|
||||||
|
popupRect.moveLeft(bounds.left());
|
||||||
|
}
|
||||||
|
if (!inBounds(popupRect, Qt::RightEdge)) {
|
||||||
|
popupRect.moveRight(bounds.right());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resizeConstraintAdjustments() & Qt::Horizontal) {
|
||||||
|
QRectF unconstrainedRect = popupRect;
|
||||||
|
|
||||||
|
if (!inBounds(unconstrainedRect, Qt::LeftEdge)) {
|
||||||
|
unconstrainedRect.setLeft(bounds.left());
|
||||||
|
}
|
||||||
|
if (!inBounds(unconstrainedRect, Qt::RightEdge)) {
|
||||||
|
unconstrainedRect.setRight(bounds.right());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unconstrainedRect.isValid()) {
|
||||||
|
popupRect = unconstrainedRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flipConstraintAdjustments() & Qt::Vertical) {
|
||||||
|
if (!inBounds(popupRect, Qt::TopEdge | Qt::BottomEdge)) {
|
||||||
|
// flip both edges (if either bit is set, XOR both)
|
||||||
|
auto flippedAnchorEdge = anchorEdges();
|
||||||
|
if (flippedAnchorEdge & (Qt::TopEdge | Qt::BottomEdge)) {
|
||||||
|
flippedAnchorEdge ^= (Qt::TopEdge | Qt::BottomEdge);
|
||||||
|
}
|
||||||
|
auto flippedGravity = gravityEdges();
|
||||||
|
if (flippedGravity & (Qt::TopEdge | Qt::BottomEdge)) {
|
||||||
|
flippedGravity ^= (Qt::TopEdge | Qt::BottomEdge);
|
||||||
|
}
|
||||||
|
auto flippedPopupRect = QRectF(KWin::popupOffset(anchorRect(), flippedAnchorEdge, flippedGravity, size()) + offset(), size());
|
||||||
|
|
||||||
|
// if it still doesn't fit we should continue with the unflipped version
|
||||||
|
if (inBounds(flippedPopupRect, Qt::TopEdge | Qt::BottomEdge)) {
|
||||||
|
popupRect.moveTop(flippedPopupRect.top());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slideConstraintAdjustments() & Qt::Vertical) {
|
||||||
|
if (!inBounds(popupRect, Qt::TopEdge)) {
|
||||||
|
popupRect.moveTop(bounds.top());
|
||||||
|
}
|
||||||
|
if (!inBounds(popupRect, Qt::BottomEdge)) {
|
||||||
|
popupRect.moveBottom(bounds.bottom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resizeConstraintAdjustments() & Qt::Vertical) {
|
||||||
|
QRectF unconstrainedRect = popupRect;
|
||||||
|
|
||||||
|
if (!inBounds(unconstrainedRect, Qt::TopEdge)) {
|
||||||
|
unconstrainedRect.setTop(bounds.top());
|
||||||
|
}
|
||||||
|
if (!inBounds(unconstrainedRect, Qt::BottomEdge)) {
|
||||||
|
unconstrainedRect.setBottom(bounds.bottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unconstrainedRect.isValid()) {
|
||||||
|
popupRect = unconstrainedRect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return popupRect;
|
||||||
|
}
|
||||||
|
|
||||||
XdgPositioner XdgPositioner::get(::wl_resource *resource)
|
XdgPositioner XdgPositioner::get(::wl_resource *resource)
|
||||||
{
|
{
|
||||||
XdgPositionerPrivate *xdgPositionerPrivate = XdgPositionerPrivate::get(resource);
|
XdgPositionerPrivate *xdgPositionerPrivate = XdgPositionerPrivate::get(resource);
|
||||||
|
|
|
@ -505,6 +505,12 @@ public:
|
||||||
*/
|
*/
|
||||||
quint32 parentConfigure() const;
|
quint32 parentConfigure() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unconstrained geometry of the popup. The \a bounds is in the parent local
|
||||||
|
* coordinate space.
|
||||||
|
*/
|
||||||
|
QRectF placement(const QRectF &bounds) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current state of the xdg positioner object identified by \a resource.
|
* Returns the current state of the xdg positioner object identified by \a resource.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1611,7 +1611,14 @@ void XdgPopupWindow::handleRepositionRequested(quint32 token)
|
||||||
void XdgPopupWindow::updateRelativePlacement()
|
void XdgPopupWindow::updateRelativePlacement()
|
||||||
{
|
{
|
||||||
const QPointF parentPosition = transientFor()->framePosToClientPos(transientFor()->pos());
|
const QPointF parentPosition = transientFor()->framePosToClientPos(transientFor()->pos());
|
||||||
m_relativePlacement = placement().translated(-parentPosition);
|
const QRectF bounds = workspace()->clientArea(transientFor()->isFullScreen() ? FullScreenArea : PlacementArea, transientFor()).translated(-parentPosition);
|
||||||
|
const XdgPositioner positioner = m_shellSurface->positioner();
|
||||||
|
|
||||||
|
if (m_plasmaShellSurface && m_plasmaShellSurface->isPositionSet()) {
|
||||||
|
m_relativePlacement = QRectF(m_plasmaShellSurface->position(), positioner.size()).translated(-parentPosition);
|
||||||
|
} else {
|
||||||
|
m_relativePlacement = positioner.placement(bounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XdgPopupWindow::relayout()
|
void XdgPopupWindow::relayout()
|
||||||
|
@ -1673,132 +1680,6 @@ QRectF XdgPopupWindow::transientPlacement() const
|
||||||
return m_relativePlacement.translated(parentPosition);
|
return m_relativePlacement.translated(parentPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF XdgPopupWindow::placement() const
|
|
||||||
{
|
|
||||||
const QRectF bounds = Workspace::self()->clientArea(transientFor()->isFullScreen() ? FullScreenArea : PlacementArea, transientFor());
|
|
||||||
|
|
||||||
const XdgPositioner positioner = m_shellSurface->positioner();
|
|
||||||
const QSize desiredSize = positioner.size();
|
|
||||||
|
|
||||||
if (m_plasmaShellSurface && m_plasmaShellSurface->isPositionSet()) {
|
|
||||||
return QRectF(m_plasmaShellSurface->position(), desiredSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QPointF parentPosition = transientFor()->framePosToClientPos(transientFor()->pos());
|
|
||||||
|
|
||||||
// returns if a target is within the supplied bounds, optional edges argument states which side to check
|
|
||||||
auto inBounds = [bounds](const QRectF &target, Qt::Edges edges = Qt::LeftEdge | Qt::RightEdge | Qt::TopEdge | Qt::BottomEdge) -> bool {
|
|
||||||
if (edges & Qt::LeftEdge && target.left() < bounds.left()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (edges & Qt::TopEdge && target.top() < bounds.top()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (edges & Qt::RightEdge && target.right() > bounds.right()) {
|
|
||||||
// normal QRect::right issue cancels out
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (edges & Qt::BottomEdge && target.bottom() > bounds.bottom()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
QRectF popupRect(popupOffset(positioner.anchorRect(), positioner.anchorEdges(), positioner.gravityEdges(), desiredSize) + positioner.offset() + parentPosition, desiredSize);
|
|
||||||
|
|
||||||
// if that fits, we don't need to do anything
|
|
||||||
if (inBounds(popupRect)) {
|
|
||||||
return popupRect;
|
|
||||||
}
|
|
||||||
// otherwise apply constraint adjustment per axis in order XDG Shell Popup states
|
|
||||||
|
|
||||||
if (positioner.flipConstraintAdjustments() & Qt::Horizontal) {
|
|
||||||
if (!inBounds(popupRect, Qt::LeftEdge | Qt::RightEdge)) {
|
|
||||||
// flip both edges (if either bit is set, XOR both)
|
|
||||||
auto flippedAnchorEdge = positioner.anchorEdges();
|
|
||||||
if (flippedAnchorEdge & (Qt::LeftEdge | Qt::RightEdge)) {
|
|
||||||
flippedAnchorEdge ^= (Qt::LeftEdge | Qt::RightEdge);
|
|
||||||
}
|
|
||||||
auto flippedGravity = positioner.gravityEdges();
|
|
||||||
if (flippedGravity & (Qt::LeftEdge | Qt::RightEdge)) {
|
|
||||||
flippedGravity ^= (Qt::LeftEdge | Qt::RightEdge);
|
|
||||||
}
|
|
||||||
auto flippedPopupRect = QRectF(popupOffset(positioner.anchorRect(), flippedAnchorEdge, flippedGravity, desiredSize) + positioner.offset() + parentPosition, desiredSize);
|
|
||||||
|
|
||||||
// if it still doesn't fit we should continue with the unflipped version
|
|
||||||
if (inBounds(flippedPopupRect, Qt::LeftEdge | Qt::RightEdge)) {
|
|
||||||
popupRect.moveLeft(flippedPopupRect.left());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (positioner.slideConstraintAdjustments() & Qt::Horizontal) {
|
|
||||||
if (!inBounds(popupRect, Qt::LeftEdge)) {
|
|
||||||
popupRect.moveLeft(bounds.left());
|
|
||||||
}
|
|
||||||
if (!inBounds(popupRect, Qt::RightEdge)) {
|
|
||||||
popupRect.moveRight(bounds.right());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (positioner.resizeConstraintAdjustments() & Qt::Horizontal) {
|
|
||||||
QRectF unconstrainedRect = popupRect;
|
|
||||||
|
|
||||||
if (!inBounds(unconstrainedRect, Qt::LeftEdge)) {
|
|
||||||
unconstrainedRect.setLeft(bounds.left());
|
|
||||||
}
|
|
||||||
if (!inBounds(unconstrainedRect, Qt::RightEdge)) {
|
|
||||||
unconstrainedRect.setRight(bounds.right());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unconstrainedRect.isValid()) {
|
|
||||||
popupRect = unconstrainedRect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (positioner.flipConstraintAdjustments() & Qt::Vertical) {
|
|
||||||
if (!inBounds(popupRect, Qt::TopEdge | Qt::BottomEdge)) {
|
|
||||||
// flip both edges (if either bit is set, XOR both)
|
|
||||||
auto flippedAnchorEdge = positioner.anchorEdges();
|
|
||||||
if (flippedAnchorEdge & (Qt::TopEdge | Qt::BottomEdge)) {
|
|
||||||
flippedAnchorEdge ^= (Qt::TopEdge | Qt::BottomEdge);
|
|
||||||
}
|
|
||||||
auto flippedGravity = positioner.gravityEdges();
|
|
||||||
if (flippedGravity & (Qt::TopEdge | Qt::BottomEdge)) {
|
|
||||||
flippedGravity ^= (Qt::TopEdge | Qt::BottomEdge);
|
|
||||||
}
|
|
||||||
auto flippedPopupRect = QRectF(popupOffset(positioner.anchorRect(), flippedAnchorEdge, flippedGravity, desiredSize) + positioner.offset() + parentPosition, desiredSize);
|
|
||||||
|
|
||||||
// if it still doesn't fit we should continue with the unflipped version
|
|
||||||
if (inBounds(flippedPopupRect, Qt::TopEdge | Qt::BottomEdge)) {
|
|
||||||
popupRect.moveTop(flippedPopupRect.top());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (positioner.slideConstraintAdjustments() & Qt::Vertical) {
|
|
||||||
if (!inBounds(popupRect, Qt::TopEdge)) {
|
|
||||||
popupRect.moveTop(bounds.top());
|
|
||||||
}
|
|
||||||
if (!inBounds(popupRect, Qt::BottomEdge)) {
|
|
||||||
popupRect.moveBottom(bounds.bottom());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (positioner.resizeConstraintAdjustments() & Qt::Vertical) {
|
|
||||||
QRectF unconstrainedRect = popupRect;
|
|
||||||
|
|
||||||
if (!inBounds(unconstrainedRect, Qt::TopEdge)) {
|
|
||||||
unconstrainedRect.setTop(bounds.top());
|
|
||||||
}
|
|
||||||
if (!inBounds(unconstrainedRect, Qt::BottomEdge)) {
|
|
||||||
unconstrainedRect.setBottom(bounds.bottom());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unconstrainedRect.isValid()) {
|
|
||||||
popupRect = unconstrainedRect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return popupRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool XdgPopupWindow::isCloseable() const
|
bool XdgPopupWindow::isCloseable() const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -261,8 +261,6 @@ protected:
|
||||||
void handleRoleDestroyed() override;
|
void handleRoleDestroyed() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRectF placement() const;
|
|
||||||
|
|
||||||
void handleGrabRequested(KWaylandServer::SeatInterface *seat, quint32 serial);
|
void handleGrabRequested(KWaylandServer::SeatInterface *seat, quint32 serial);
|
||||||
void handleRepositionRequested(quint32 token);
|
void handleRepositionRequested(quint32 token);
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
Loading…
Reference in a new issue