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 "="