QWaylandSurface: client support wl_surface version 6

Add QWaylandWindow::updateScale() function to update the window's scale
from QWaylandFractionalScale or QWaylandSurface::preferredBufferScale or
QWaylandScreen::scale or QWaylandSurface::preferredBufferScale.

Add QWaylandWindow::updateBufferTransform() function to update the
window's buffer transform from QScreen::primaryOrientation or
QWaylandSurface::preferredBufferTransform.

Change-Id: I2742701e92c7403a89df97b7fa06b5b0de6917a7
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: David Edmundson <davidedmundson@kde.org>
This commit is contained in:
JiDe Zhang 2023-09-20 16:59:57 +08:00
parent 7666f93b3b
commit e73979a94f
9 changed files with 131 additions and 50 deletions

View File

@ -618,7 +618,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
if (interface == QLatin1String(QtWayland::wl_output::interface()->name)) {
mWaitingScreens << mWaylandIntegration->createPlatformScreen(this, version, id);
} else if (interface == QLatin1String(QtWayland::wl_compositor::interface()->name)) {
mCompositor.init(registry, id, qMin((int)version, 4));
mCompositor.init(registry, id, qMin((int)version, 6));
} else if (interface == QLatin1String(QWaylandShm::interface()->name)) {
mShm.reset(new QWaylandShm(this, version, id));
} else if (interface == QLatin1String(QWaylandInputDevice::interface()->name)) {

View File

@ -22,7 +22,7 @@ void QWaylandFractionalScale::wp_fractional_scale_v1_preferred_scale(uint scale)
qreal preferredScale = scale / 120.0; // hardcoded denominator determined in the spec
if (preferredScale != mPreferredScale) {
mPreferredScale = preferredScale;
Q_EMIT preferredScaleChanged(preferredScale);
Q_EMIT preferredScaleChanged();
}
}

View File

@ -33,8 +33,10 @@ public:
explicit QWaylandFractionalScale(struct ::wp_fractional_scale_v1 *object);
~QWaylandFractionalScale();
std::optional<qreal> preferredScale() const { return mPreferredScale; }
Q_SIGNALS:
void preferredScaleChanged(qreal preferredScale);
void preferredScaleChanged();
protected:
void wp_fractional_scale_v1_preferred_scale(uint scale) override;

View File

@ -205,6 +205,35 @@ QWaylandScreen *QWaylandScreen::fromWlOutput(::wl_output *output)
return nullptr;
}
Qt::ScreenOrientation QWaylandScreen::toScreenOrientation(int wlTransform,
Qt::ScreenOrientation fallback) const
{
auto orientation = fallback;
bool isPortrait = mGeometry.height() > mGeometry.width();
switch (wlTransform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
orientation = isPortrait ? Qt::PortraitOrientation : Qt::LandscapeOrientation;
break;
case WL_OUTPUT_TRANSFORM_90:
orientation = isPortrait ? Qt::InvertedLandscapeOrientation : Qt::PortraitOrientation;
break;
case WL_OUTPUT_TRANSFORM_180:
orientation = isPortrait ? Qt::InvertedPortraitOrientation : Qt::InvertedLandscapeOrientation;
break;
case WL_OUTPUT_TRANSFORM_270:
orientation = isPortrait ? Qt::LandscapeOrientation : Qt::InvertedPortraitOrientation;
break;
// Ignore these ones, at least for now
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
break;
}
return orientation;
}
void QWaylandScreen::output_mode(uint32_t flags, int width, int height, int refresh)
{
if (!(flags & WL_OUTPUT_MODE_CURRENT))
@ -257,29 +286,11 @@ void QWaylandScreen::output_done()
void QWaylandScreen::updateOutputProperties()
{
if (mTransform >= 0) {
bool isPortrait = mGeometry.height() > mGeometry.width();
switch (mTransform) {
case WL_OUTPUT_TRANSFORM_NORMAL:
m_orientation = isPortrait ? Qt::PortraitOrientation : Qt::LandscapeOrientation;
break;
case WL_OUTPUT_TRANSFORM_90:
m_orientation = isPortrait ? Qt::InvertedLandscapeOrientation : Qt::PortraitOrientation;
break;
case WL_OUTPUT_TRANSFORM_180:
m_orientation = isPortrait ? Qt::InvertedPortraitOrientation : Qt::InvertedLandscapeOrientation;
break;
case WL_OUTPUT_TRANSFORM_270:
m_orientation = isPortrait ? Qt::LandscapeOrientation : Qt::InvertedPortraitOrientation;
break;
// Ignore these ones, at least for now
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
break;
auto newOrientation = toScreenOrientation(mTransform, m_orientation);
if (m_orientation != newOrientation) {
m_orientation = newOrientation;
QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation);
}
QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation);
mTransform = -1;
}

View File

@ -82,6 +82,9 @@ public:
static QWaylandScreen *waylandScreenFromWindow(QWindow *window);
static QWaylandScreen *fromWlOutput(::wl_output *output);
Qt::ScreenOrientation toScreenOrientation(int wlTransform,
Qt::ScreenOrientation fallback) const;
protected:
enum Event : uint {
XdgOutputDoneEvent = 0x1,

View File

@ -85,6 +85,22 @@ void QWaylandSurface::surface_leave(wl_output *output)
emit screensChanged();
}
void QWaylandSurface::surface_preferred_buffer_scale(int32_t scale)
{
if (m_preferredBufferScale == scale)
return;
m_preferredBufferScale = scale;
Q_EMIT preferredBufferScaleChanged();
}
void QWaylandSurface::surface_preferred_buffer_transform(uint32_t transform)
{
if (m_preferredBufferTransform == transform)
return;
m_preferredBufferTransform = static_cast<wl_output_transform>(transform);
Q_EMIT preferredBufferTransformChanged();
}
} // namespace QtWaylandClient
QT_END_NAMESPACE

View File

@ -36,11 +36,15 @@ public:
~QWaylandSurface() override;
QWaylandScreen *oldestEnteredScreen();
QWaylandWindow *waylandWindow() const { return m_window; }
std::optional<int32_t> preferredBufferScale() const { return m_preferredBufferScale; }
std::optional<wl_output_transform> preferredBufferTransform() const { return m_preferredBufferTransform; }
static QWaylandSurface *fromWlSurface(::wl_surface *surface);
signals:
void screensChanged();
void preferredBufferScaleChanged();
void preferredBufferTransformChanged();
private slots:
void handleScreenRemoved(QScreen *qScreen);
@ -48,9 +52,13 @@ private slots:
protected:
void surface_enter(struct ::wl_output *output) override;
void surface_leave(struct ::wl_output *output) override;
void surface_preferred_buffer_scale(int32_t scale) override;
void surface_preferred_buffer_transform(uint32_t transform) override;
QList<QWaylandScreen *> m_screens; //As seen by wl_surface.enter/leave events. Chronological order.
QWaylandWindow *m_window = nullptr;
std::optional<int32_t> m_preferredBufferScale;
std::optional<wl_output_transform> m_preferredBufferTransform;
friend class QWaylandWindow; // TODO: shouldn't need to be friends
};

View File

@ -105,11 +105,8 @@ void QWaylandWindow::initWindow()
if (mDisplay->fractionalScaleManager() && qApp->highDpiScaleFactorRoundingPolicy() == Qt::HighDpiScaleFactorRoundingPolicy::PassThrough) {
mFractionalScale.reset(new QWaylandFractionalScale(mDisplay->fractionalScaleManager()->get_fractional_scale(mSurface->object())));
connect(mFractionalScale.data(), &QWaylandFractionalScale::preferredScaleChanged, this, [this](qreal preferredScale) {
preferredScale = std::max(1.0, preferredScale);
Q_ASSERT(mViewport);
setScale(preferredScale);
});
connect(mFractionalScale.data(), &QWaylandFractionalScale::preferredScaleChanged,
this, &QWaylandWindow::updateScale);
}
if (shouldCreateSubSurface()) {
@ -209,6 +206,10 @@ void QWaylandWindow::initializeWlSurface()
mSurface.reset(new QWaylandSurface(mDisplay));
connect(mSurface.data(), &QWaylandSurface::screensChanged,
this, &QWaylandWindow::handleScreensChanged);
connect(mSurface.data(), &QWaylandSurface::preferredBufferScaleChanged,
this, &QWaylandWindow::updateScale);
connect(mSurface.data(), &QWaylandSurface::preferredBufferTransformChanged,
this, &QWaylandWindow::updateBufferTransform);
mSurface->m_window = this;
}
emit wlSurfaceCreated();
@ -941,31 +942,49 @@ QWaylandScreen *QWaylandWindow::waylandScreen() const
}
void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
{
mLastReportedContentOrientation = orientation;
updateBufferTransform();
}
void QWaylandWindow::updateBufferTransform()
{
QReadLocker locker(&mSurfaceLock);
if (mSurface == nullptr || mSurface->version() < 2)
return;
wl_output_transform transform;
bool isPortrait = window()->screen() && window()->screen()->primaryOrientation() == Qt::PortraitOrientation;
switch (orientation) {
case Qt::PrimaryOrientation:
transform = WL_OUTPUT_TRANSFORM_NORMAL;
break;
case Qt::LandscapeOrientation:
transform = isPortrait ? WL_OUTPUT_TRANSFORM_270 : WL_OUTPUT_TRANSFORM_NORMAL;
break;
case Qt::PortraitOrientation:
transform = isPortrait ? WL_OUTPUT_TRANSFORM_NORMAL : WL_OUTPUT_TRANSFORM_90;
break;
case Qt::InvertedLandscapeOrientation:
transform = isPortrait ? WL_OUTPUT_TRANSFORM_90 : WL_OUTPUT_TRANSFORM_180;
break;
case Qt::InvertedPortraitOrientation:
transform = isPortrait ? WL_OUTPUT_TRANSFORM_180 : WL_OUTPUT_TRANSFORM_270;
break;
default:
Q_UNREACHABLE();
Qt::ScreenOrientation screenOrientation = Qt::PrimaryOrientation;
if (mSurface->version() >= 6) {
const auto transform = mSurface->preferredBufferTransform().value_or(WL_OUTPUT_TRANSFORM_NORMAL);
if (auto screen = waylandScreen())
screenOrientation = screen->toScreenOrientation(transform, Qt::PrimaryOrientation);
} else {
if (auto screen = window()->screen())
screenOrientation = screen->primaryOrientation();
}
const bool isPortrait = (screenOrientation == Qt::PortraitOrientation);
switch (mLastReportedContentOrientation) {
case Qt::PrimaryOrientation:
transform = WL_OUTPUT_TRANSFORM_NORMAL;
break;
case Qt::LandscapeOrientation:
transform = isPortrait ? WL_OUTPUT_TRANSFORM_270 : WL_OUTPUT_TRANSFORM_NORMAL;
break;
case Qt::PortraitOrientation:
transform = isPortrait ? WL_OUTPUT_TRANSFORM_NORMAL : WL_OUTPUT_TRANSFORM_90;
break;
case Qt::InvertedLandscapeOrientation:
transform = isPortrait ? WL_OUTPUT_TRANSFORM_90 : WL_OUTPUT_TRANSFORM_180;
break;
case Qt::InvertedPortraitOrientation:
transform = isPortrait ? WL_OUTPUT_TRANSFORM_180 : WL_OUTPUT_TRANSFORM_270;
break;
default:
Q_UNREACHABLE();
}
mSurface->set_buffer_transform(transform);
}
@ -1379,8 +1398,26 @@ void QWaylandWindow::handleScreensChanged()
setGeometry(geometry);
}
if (mFractionalScale)
updateScale();
updateBufferTransform();
}
void QWaylandWindow::updateScale()
{
if (mFractionalScale) {
auto preferredScale = mFractionalScale->preferredScale().value_or(1.0);
preferredScale = std::max(1.0, preferredScale);
Q_ASSERT(mViewport);
setScale(preferredScale);
return;
}
if (mSurface && mSurface->version() >= 6) {
auto preferredScale = mSurface->preferredBufferScale().value_or(1);
preferredScale = std::max(1, preferredScale);
setScale(preferredScale);
return;
}
int scale = mLastReportedScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(mLastReportedScreen)->scale();
setScale(scale);

View File

@ -142,6 +142,7 @@ public:
QWaylandScreen *waylandScreen() const;
void handleContentOrientationChange(Qt::ScreenOrientation orientation) override;
void updateBufferTransform();
void setOrientationMask(Qt::ScreenOrientations mask);
ToplevelWindowTilingStates toplevelWindowTilingStates() const;
@ -331,6 +332,8 @@ protected:
QPointer<QWaylandWindow> mTransientParent;
QList<QPointer<QWaylandWindow>> mChildPopups;
Qt::ScreenOrientation mLastReportedContentOrientation = Qt::PrimaryOrientation;
private slots:
void doApplyConfigureFromOtherThread();
@ -348,6 +351,7 @@ private:
void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
void handleScreensChanged();
void updateScale();
void setScale(qreal newScale);
void sendRecursiveExposeEvent();