MadRunner
MadRunner

Reputation: 640

Prevent Qt::Popup from going beyond screen border on wayland

I show some complex QWidget as Qt::Popup at certain position of parent window. Specifically I want it to stick to the selected text:

this part is trivial, but when there is no enough space to the right or below, it should move in the available direction:

On X (and probably other platforms?) I can calculate global (screen) coordinates and select best direction so that no obstruction occurs, but wayland for a bunch of reasons doesn't let you manipulate or even query global coordinates.

How can something like this be achieved then? What are the alternatives?

Upvotes: 0

Views: 45

Answers (1)

MadRunner
MadRunner

Reputation: 640

QtWyaland uses XDG Shell protocol, Qt::Popup specifically is reflected on xdg_popup and constraints on it's geometry are set with xdg_positioner.

QtWayland does set constraints on popups, but the defaults aren't always the best:

(here popup is prevented from going below screen border by sliding up and completely covering selected text)

Digging through QtWayland sources (version 6.8) you can find an undocumented api for overriding xdg_positioner configuration, which then can be used in something like:

void MyPopup::showEvent(QShowEvent *event)
{
    QFrame::showEvent(event);

    QRect cursorRect = // ...
    move(cursorRect.bottomLeft());

    QWindow* window = windowHandle();
    window->setProperty("_q_waylandPopupAnchorRect", cursorRect);
    window->setProperty("_q_waylandPopupAnchor", QVariant::fromValue(Qt::BottomEdge | Qt::LeftEdge));
    window->setProperty("_q_waylandPopupGravity", QVariant::fromValue(Qt::BottomEdge | Qt::LeftEdge));
    window->setProperty("_q_waylandPopupConstraintAdjustment", (
        QtWayland::xdg_positioner::constraint_adjustment_slide_x
        | QtWayland::xdg_positioner::constraint_adjustment_flip_x
        | QtWayland::xdg_positioner::constraint_adjustment_flip_y
        | QtWayland::xdg_positioner::constraint_adjustment_resize_x
        | QtWayland::xdg_positioner::constraint_adjustment_resize_y
    ));
}

(QtWayland::xdg_positioner requires linking to Qt6::WaylandClientPrivate, but you may just hardcode required constants)

Of course, don't forget to wrap the code in platform check and implement alternatives for other platforms.

Upvotes: 1

Related Questions