Changeset View
Changeset View
Standalone View
Standalone View
shell_client.cpp
| Show First 20 Lines • Show All 321 Lines • ▼ Show 20 Line(s) | 207 | { | |||
|---|---|---|---|---|---|
| 322 | } else if (m_xdgShellPopup) { | 322 | } else if (m_xdgShellPopup) { | ||
| 323 | connect(m_xdgShellPopup, &XdgShellPopupInterface::grabRequested, this, [this](SeatInterface *seat, quint32 serial) { | 323 | connect(m_xdgShellPopup, &XdgShellPopupInterface::grabRequested, this, [this](SeatInterface *seat, quint32 serial) { | ||
| 324 | Q_UNUSED(seat) | 324 | Q_UNUSED(seat) | ||
| 325 | Q_UNUSED(serial) | 325 | Q_UNUSED(serial) | ||
| 326 | //TODO - should check the parent had focus | 326 | //TODO - should check the parent had focus | ||
| 327 | m_hasPopupGrab = true; | 327 | m_hasPopupGrab = true; | ||
| 328 | }); | 328 | }); | ||
| 329 | 329 | | |||
| 330 | connect(m_xdgShellSurface, &XdgShellSurfaceInterface::configureAcknowledged, this, [this](int serial) { | 330 | connect(m_xdgShellPopup, &XdgShellPopupInterface::configureAcknowledged, this, [this](int serial) { | ||
| 331 | m_lastAckedConfigureRequest = serial; | 331 | m_lastAckedConfigureRequest = serial; | ||
| 332 | }); | 332 | }); | ||
| 333 | 333 | | |||
| 334 | QRect position = QRect(m_xdgShellPopup->transientOffset(), m_xdgShellPopup->initialSize()); | 334 | QRect position = QRect(m_xdgShellPopup->transientOffset(), m_xdgShellPopup->initialSize()); | ||
| 335 | m_xdgShellPopup->configure(position); | 335 | m_xdgShellPopup->configure(position); | ||
| 336 | 336 | | |||
| 337 | connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient); | 337 | connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient); | ||
| 338 | } | 338 | } | ||
| ▲ Show 20 Lines • Show All 1230 Lines • ▼ Show 20 Line(s) | 1568 | if (t) { | |||
| 1569 | t->addTransient(this); | 1569 | t->addTransient(this); | ||
| 1570 | } | 1570 | } | ||
| 1571 | } | 1571 | } | ||
| 1572 | m_transient = (s != nullptr); | 1572 | m_transient = (s != nullptr); | ||
| 1573 | } | 1573 | } | ||
| 1574 | 1574 | | |||
| 1575 | bool ShellClient::hasTransientPlacementHint() const | 1575 | bool ShellClient::hasTransientPlacementHint() const | ||
| 1576 | { | 1576 | { | ||
| 1577 | return isTransient() && transientFor() != nullptr; | 1577 | return isTransient() && transientFor() != nullptr && | ||
| 1578 | (m_shellSurface || m_xdgShellPopup); | ||||
| 1578 | } | 1579 | } | ||
| 1579 | 1580 | | |||
| 1580 | QPoint ShellClient::transientPlacementHint() const | 1581 | QRect ShellClient::transientPlacement(const QRect &bounds) const | ||
| 1581 | { | 1582 | { | ||
| 1583 | QRect anchorRect; | ||||
| 1584 | Qt::Edges anchorEdge; | ||||
| 1585 | Qt::Edges gravity; | ||||
| 1586 | QPoint offset; | ||||
| 1587 | PositionerConstraints constraintAdjustments; | ||||
| 1588 | | ||||
| 1589 | const QPoint parentClientPos = transientFor()->pos() + transientFor()->clientPos(); | ||||
| 1590 | QRect popupPosition; | ||||
| 1591 | | ||||
| 1592 | // returns if a target is within the supplied bounds, optional edges argument states which side to check | ||||
| 1593 | auto inBounds = [bounds](const QRect &target, Qt::Edges edges = Qt::LeftEdge | Qt::RightEdge | Qt::TopEdge | Qt::BottomEdge) -> bool { | ||||
| 1594 | if (edges & Qt::LeftEdge && target.left() < bounds.left()) { | ||||
| 1595 | return false; | ||||
| 1596 | } | ||||
| 1597 | if (edges & Qt::TopEdge && target.top() < bounds.top()) { | ||||
| 1598 | return false; | ||||
| 1599 | } | ||||
| 1600 | if (edges & Qt::RightEdge && target.right() > bounds.right()) { | ||||
| 1601 | //normal QRect::right issue cancels out | ||||
| 1602 | return false; | ||||
| 1603 | } | ||||
| 1604 | if (edges & Qt::BottomEdge && target.bottom() > bounds.bottom()) { | ||||
| 1605 | return false; | ||||
| 1606 | } | ||||
| 1607 | return true; | ||||
| 1608 | }; | ||||
| 1609 | | ||||
| 1582 | if (m_shellSurface) { | 1610 | if (m_shellSurface) { | ||
| 1583 | return m_shellSurface->transientOffset(); | 1611 | anchorRect = QRect(m_shellSurface->transientOffset(), QSize(1,1)); | ||
| 1612 | anchorEdge = Qt::TopEdge | Qt::LeftEdge; | ||||
| 1613 | gravity = Qt::BottomEdge | Qt::RightEdge; //our single point represents the top left of the popup | ||||
| 1614 | constraintAdjustments = (PositionerConstraint::SlideX | PositionerConstraint::SlideY); | ||||
| 1615 | } else if (m_xdgShellPopup) { | ||||
| 1616 | anchorRect = m_xdgShellPopup->anchorRect(); | ||||
| 1617 | anchorEdge = m_xdgShellPopup->anchorEdge(); | ||||
| 1618 | gravity = m_xdgShellPopup->gravity(); | ||||
| 1619 | offset = m_xdgShellPopup->anchorOffset(); | ||||
zzag: Missing whitespace before "=" | |||||
| 1620 | constraintAdjustments = m_xdgShellPopup->constraintAdjustments(); | ||||
| 1621 | } else { | ||||
| 1622 | Q_UNREACHABLE(); | ||||
zzag: Q_UNREACHABLE | |||||
zzag: ... or Q_ASSERT_X to print more "user"-friendly message. | |||||
This is the one of the few times where Q_UNREACHABLE actually saves a single jump instruction. May as well, given it documents the assert better. davidedmundson: This is the one of the few times where Q_UNREACHABLE actually saves a single jump instruction. | |||||
| 1584 | } | 1623 | } | ||
| 1585 | if (m_xdgShellPopup) { | 1624 | | ||
| 1586 | return m_xdgShellPopup->transientOffset(); | 1625 | //initial position | ||
| 1626 | popupPosition = QRect(popupOffset(anchorRect, anchorEdge, gravity) + offset + parentClientPos, geometry().size()); | ||||
| 1627 | | ||||
| 1628 | //if that fits, we don't need to do anything | ||||
| 1629 | if (inBounds(popupPosition)) { | ||||
| 1630 | return popupPosition; | ||||
| 1631 | } | ||||
| 1632 | //otherwise apply constraint adjustment per axis in order XDG Shell Popup states | ||||
| 1633 | | ||||
| 1634 | if (constraintAdjustments & PositionerConstraint::FlipX) { | ||||
| 1635 | if (!inBounds(popupPosition, Qt::LeftEdge | Qt::RightEdge)) { | ||||
| 1636 | //flip both edges (if either bit is set, XOR both) | ||||
| 1637 | auto flippedAnchorEdge = anchorEdge; | ||||
| 1638 | if (flippedAnchorEdge & (Qt::LeftEdge | Qt::RightEdge)) { | ||||
| 1639 | flippedAnchorEdge ^= (Qt::LeftEdge | Qt::RightEdge); | ||||
| 1640 | } | ||||
| 1641 | auto flippedGravity = gravity; | ||||
| 1642 | if (flippedGravity & (Qt::LeftEdge | Qt::RightEdge)) { | ||||
zzag: Aren't FlipX and FlipY having precedence over SlideX and SlideY respectively? | |||||
davidedmundson: heh, the spec lists slide first in the enum
But yeah, we should. | |||||
| 1643 | flippedGravity ^= (Qt::LeftEdge | Qt::RightEdge); | ||||
| 1644 | } | ||||
| 1645 | auto flippedPopupPosition = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity) + offset + parentClientPos, geometry().size()); | ||||
| 1646 | | ||||
| 1647 | //if it still doesn't fit we should continue with the unflipped version | ||||
| 1648 | if (inBounds(flippedPopupPosition, Qt::LeftEdge | Qt::RightEdge)) { | ||||
| 1649 | popupPosition.setX(flippedPopupPosition.x()); | ||||
| 1650 | } | ||||
| 1651 | } | ||||
| 1652 | } | ||||
| 1653 | if (constraintAdjustments & PositionerConstraint::SlideX) { | ||||
| 1654 | if (!inBounds(popupPosition, Qt::LeftEdge)) { | ||||
| 1655 | popupPosition.setX(bounds.x()); | ||||
| 1656 | } | ||||
| 1657 | if (!inBounds(popupPosition, Qt::RightEdge)) { | ||||
| 1658 | popupPosition.setX(bounds.x() + bounds.width() - geometry().width()); | ||||
| 1659 | } | ||||
| 1660 | } | ||||
| 1661 | if (constraintAdjustments & PositionerConstraint::ResizeX) { | ||||
| 1662 | //TODO | ||||
| 1663 | //but we need to sort out when this is run as resize should only happen before first configure | ||||
| 1664 | } | ||||
| 1665 | | ||||
| 1666 | if (constraintAdjustments & PositionerConstraint::FlipY) { | ||||
| 1667 | if (!inBounds(popupPosition, Qt::TopEdge | Qt::BottomEdge)) { | ||||
| 1668 | //flip both edges (if either bit is set, XOR both) | ||||
| 1669 | auto flippedAnchorEdge = anchorEdge; | ||||
| 1670 | if (flippedAnchorEdge & (Qt::TopEdge | Qt::BottomEdge)) { | ||||
| 1671 | flippedAnchorEdge ^= (Qt::TopEdge | Qt::BottomEdge); | ||||
| 1672 | } | ||||
| 1673 | auto flippedGravity = gravity; | ||||
| 1674 | if (flippedGravity & (Qt::TopEdge | Qt::BottomEdge)) { | ||||
| 1675 | flippedGravity ^= (Qt::TopEdge | Qt::BottomEdge); | ||||
| 1676 | } | ||||
| 1677 | auto flippedPopupPosition = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity) + offset + parentClientPos, geometry().size()); | ||||
| 1678 | | ||||
| 1679 | //if it still doesn't fit we should continue with the unflipped version | ||||
| 1680 | if (inBounds(flippedPopupPosition, Qt::TopEdge | Qt::BottomEdge)) { | ||||
| 1681 | popupPosition.setY(flippedPopupPosition.y()); | ||||
| 1682 | } | ||||
| 1683 | } | ||||
| 1684 | } | ||||
| 1685 | if (constraintAdjustments & PositionerConstraint::SlideY) { | ||||
| 1686 | if (!inBounds(popupPosition, Qt::TopEdge)) { | ||||
| 1687 | popupPosition.setY(bounds.y()); | ||||
| 1688 | } | ||||
| 1689 | if (!inBounds(popupPosition, Qt::BottomEdge)) { | ||||
| 1690 | popupPosition.setY(bounds.y() + bounds.height() - geometry().height()); | ||||
| 1691 | } | ||||
| 1692 | } | ||||
| 1693 | if (constraintAdjustments & PositionerConstraint::ResizeY) { | ||||
| 1694 | //TODO | ||||
| 1695 | } | ||||
| 1696 | | ||||
| 1697 | return popupPosition; | ||||
| 1698 | } | ||||
| 1699 | | ||||
| 1700 | QPoint ShellClient::popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity) const | ||||
| 1701 | { | ||||
| 1702 | const QSize popupSize = geometry().size(); | ||||
| 1703 | QPoint anchorPoint; | ||||
| 1704 | switch (anchorEdge & (Qt::LeftEdge | Qt::RightEdge)) { | ||||
zzag: Missing whitespace between "switch" and "(" | |||||
| 1705 | case Qt::LeftEdge: | ||||
| 1706 | anchorPoint.setX(anchorRect.x()); | ||||
| 1707 | break; | ||||
| 1708 | case Qt::RightEdge: | ||||
| 1709 | anchorPoint.setX(anchorRect.x() + anchorRect.width()); | ||||
| 1710 | break; | ||||
| 1711 | default: | ||||
| 1712 | anchorPoint.setX(qRound(anchorRect.x() + anchorRect.width() / 2.0)); | ||||
| 1713 | } | ||||
| 1714 | switch (anchorEdge & (Qt::TopEdge | Qt::BottomEdge)) { | ||||
| 1715 | case Qt::TopEdge: | ||||
| 1716 | anchorPoint.setY(anchorRect.y()); | ||||
| 1717 | break; | ||||
| 1718 | case Qt::BottomEdge: | ||||
| 1719 | anchorPoint.setY(anchorRect.y() + anchorRect.height()); | ||||
| 1720 | break; | ||||
| 1721 | default: | ||||
| 1722 | anchorPoint.setY(qRound(anchorRect.y() + anchorRect.height() / 2.0)); | ||||
| 1723 | } | ||||
| 1724 | | ||||
| 1725 | // calculate where the top left point of the popup will end up with the applied gravity | ||||
| 1726 | // gravity indicates direction. i.e if gravitating towards the top the popup's bottom edge | ||||
| 1727 | // will next to the anchor point | ||||
| 1728 | QPoint popupPosAdjust; | ||||
| 1729 | switch (gravity & (Qt::LeftEdge | Qt::RightEdge)) { | ||||
| 1730 | case Qt::LeftEdge: | ||||
| 1731 | popupPosAdjust.setX(-popupSize.width()); | ||||
| 1732 | break; | ||||
| 1733 | case Qt::RightEdge: | ||||
| 1734 | popupPosAdjust.setX(0); | ||||
| 1735 | break; | ||||
| 1736 | default: | ||||
| 1737 | popupPosAdjust.setX(qRound(-popupSize.width() / 2.0)); | ||||
| 1738 | } | ||||
| 1739 | switch (gravity & (Qt::TopEdge | Qt::BottomEdge)) { | ||||
| 1740 | case Qt::TopEdge: | ||||
| 1741 | popupPosAdjust.setY(-popupSize.height()); | ||||
| 1742 | break; | ||||
| 1743 | case Qt::BottomEdge: | ||||
| 1744 | popupPosAdjust.setY(0); | ||||
| 1745 | break; | ||||
| 1746 | default: | ||||
| 1747 | popupPosAdjust.setY(qRound(-popupSize.height() / 2.0)); | ||||
| 1587 | } | 1748 | } | ||
| 1588 | return QPoint(); | 1749 | | ||
| 1750 | return anchorPoint + popupPosAdjust; | ||||
| 1589 | } | 1751 | } | ||
| 1590 | 1752 | | |||
| 1591 | bool ShellClient::isWaitingForMoveResizeSync() const | 1753 | bool ShellClient::isWaitingForMoveResizeSync() const | ||
| 1592 | { | 1754 | { | ||
| 1593 | return !m_pendingConfigureRequests.isEmpty(); | 1755 | return !m_pendingConfigureRequests.isEmpty(); | ||
| 1594 | } | 1756 | } | ||
| 1595 | 1757 | | |||
| 1596 | void ShellClient::doResizeSync() | 1758 | void ShellClient::doResizeSync() | ||
| ▲ Show 20 Lines • Show All 189 Lines • Show Last 20 Lines | |||||
Missing whitespace before "="