Skip to content

Commit

Permalink
Expose platform outputs to compositors
Browse files Browse the repository at this point in the history
Introduce OutputsModel that together with Output can be used from
QML to access platform outputs.

Compositors will use it to create WaylandOutput instrances for
each platform output.

Closes: #47
  • Loading branch information
plfiorini committed Jan 21, 2024
1 parent 40fb898 commit 3b30883
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 3 deletions.
4 changes: 3 additions & 1 deletion src/compositor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ liri_add_module(AuroraCompositor
LIBRARIES
Qt6::GuiPrivate
Liri::AuroraGlobalPrivate
Liri::AuroraPlatform
PKGCONFIG_DEPENDENCIES
Qt6Core
Qt6Gui
Expand Down Expand Up @@ -235,7 +236,8 @@ if (TARGET Qt6::Qml)
URI Aurora.Compositor
VERSION 1.0
GENERATE_PLUGIN_SOURCE
DEPENDENCIES QtQuick
DEPENDENCIES Qt.Quick
IMPORTS Aurora.Platform
)

ecm_target_qml_sources(AuroraCompositor
Expand Down
116 changes: 116 additions & 0 deletions src/compositor/compositor_api/aurorawaylandoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,64 @@ void WaylandOutputPrivate::handleWindowPixelSizeChanged()
}
}

WaylandOutput::Subpixel
WaylandOutputPrivate::convertSubpixel(const Aurora::Platform::Output::Subpixel &subpixel)
{
switch (subpixel) {
case Aurora::Platform::Output::Subpixel::Unknown:
return WaylandOutput::SubpixelUnknown;
case Aurora::Platform::Output::Subpixel::None:
return WaylandOutput::SubpixelNone;
case Aurora::Platform::Output::Subpixel::HorizontalRGB:
return WaylandOutput::SubpixelHorizontalRgb;
case Aurora::Platform::Output::Subpixel::HorizontalBGR:
return WaylandOutput::SubpixelHorizontalBgr;
case Aurora::Platform::Output::Subpixel::VerticalRGB:
return WaylandOutput::SubpixelVerticalRgb;
case Aurora::Platform::Output::Subpixel::VerticalBGR:
return WaylandOutput::SubpixelVerticalBgr;
}
}

WaylandOutput::Transform
WaylandOutputPrivate::convertTransform(const Aurora::Platform::Output::Transform &transform)
{
switch (transform) {
case Aurora::Platform::Output::Transform::Normal:
return WaylandOutput::TransformNormal;
case Aurora::Platform::Output::Transform::Rotated90:
return WaylandOutput::Transform90;
case Aurora::Platform::Output::Transform::Rotated180:
return WaylandOutput::Transform180;
case Aurora::Platform::Output::Transform::Rotated270:
return WaylandOutput::Transform270;
case Aurora::Platform::Output::Transform::Flipped:
return WaylandOutput::TransformFlipped;
case Aurora::Platform::Output::Transform::Flipped90:
return WaylandOutput::TransformFlipped90;
case Aurora::Platform::Output::Transform::Flipped180:
return WaylandOutput::TransformFlipped180;
case Aurora::Platform::Output::Transform::Flipped270:
return WaylandOutput::TransformFlipped270;
}
}

void WaylandOutputPrivate::addModesFromPlatformOutput()
{
Q_Q(WaylandOutput);

if (platformOutput) {
const auto modes = platformOutput->modes();
for (const auto &mode : modes) {
WaylandOutputMode waylandMode(mode.size, mode.refreshRate);
q->addMode(waylandMode);

if (mode.flags.testFlag(Aurora::Platform::Output::Mode::Flag::Current))
q->setCurrentMode(waylandMode);
}
}
}

void WaylandOutputPrivate::addView(WaylandView *view, WaylandSurface *surface)
{
for (int i = 0; i < surfaceViews.size(); i++) {
Expand Down Expand Up @@ -928,6 +986,64 @@ void WaylandOutput::sendFrameCallbacks()
wl_display_flush_clients(d->compositor->display());
}

Aurora::Platform::Output *WaylandOutput::platformOutput() const
{
Q_D(const WaylandOutput);
return d->platformOutput;
}

void WaylandOutput::setPlatformOutput(Aurora::Platform::Output *platformOutput)
{
Q_D(WaylandOutput);

if (d->platformOutput == platformOutput)
return;

if (d->initialized) {
qWarning("Setting PlatformOutput %p on WaylandOutput %p is not "
"supported after WaylandOutput has been initialized",
static_cast<void *>(platformOutput), static_cast<void *>(this));
return;
}

d->platformOutput = platformOutput;
Q_EMIT platformOutputChanged();

if (platformOutput) {
if (d->sizeFollowsWindow) {
setSizeFollowsWindow(false);
qWarning("WaylandOutput is directly retrieving information from the "
"underlying platform: size follows window has been disabled");
}

setPosition(d->platformOutput->globalPosition());
setManufacturer(d->platformOutput->manufacturer());
setModel(d->platformOutput->model());
setPhysicalSize(d->platformOutput->physicalSize());
setSubpixel(d->convertSubpixel(d->platformOutput->subpixel()));
setTransform(d->convertTransform(d->platformOutput->transform()));
setScaleFactor(d->platformOutput->scale());

d->addModesFromPlatformOutput();

connect(d->platformOutput, &Aurora::Platform::Output::modeAdded, this,
[this](const Aurora::Platform::Output::Mode &mode) {
WaylandOutputMode waylandMode(mode.size, mode.refreshRate);
addMode(waylandMode);

if (mode.flags.testFlag(Aurora::Platform::Output::Mode::Flag::Current))
setCurrentMode(waylandMode);
});
connect(d->platformOutput, &Aurora::Platform::Output::modeChanged, this,
[this](const Aurora::Platform::Output::Mode &mode) {
WaylandOutputMode waylandMode(mode.size, mode.refreshRate);
setCurrentMode(waylandMode);
});
} else {
disconnect(d->platformOutput, nullptr, this, nullptr);
}
}

/*!
* \internal
*/
Expand Down
7 changes: 7 additions & 0 deletions src/compositor/compositor_api/aurorawaylandoutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <QtCore/QRect>
#include <QtCore/QSize>

#include <LiriAuroraPlatform/Output>

struct wl_resource;

class QWindow;
Expand Down Expand Up @@ -41,6 +43,7 @@ class LIRIAURORACOMPOSITOR_EXPORT WaylandOutput : public WaylandObject
Q_PROPERTY(Aurora::Compositor::WaylandOutput::Transform transform READ transform WRITE setTransform NOTIFY transformChanged)
Q_PROPERTY(int scaleFactor READ scaleFactor WRITE setScaleFactor NOTIFY scaleFactorChanged)
Q_PROPERTY(bool sizeFollowsWindow READ sizeFollowsWindow WRITE setSizeFollowsWindow NOTIFY sizeFollowsWindowChanged)
Q_PROPERTY(Aurora::Platform::Output *platformOutput READ platformOutput WRITE setPlatformOutput NOTIFY platformOutputChanged)

QML_NAMED_ELEMENT(WaylandOutputBase)
QML_ADDED_IN_VERSION(1, 0)
Expand Down Expand Up @@ -120,6 +123,9 @@ class LIRIAURORACOMPOSITOR_EXPORT WaylandOutput : public WaylandObject
bool physicalSizeFollowsSize() const;
void setPhysicalSizeFollowsSize(bool follow);

Aurora::Platform::Output *platformOutput() const;
void setPlatformOutput(Aurora::Platform::Output *platformOutput);

void frameStarted();
void sendFrameCallbacks();

Expand All @@ -145,6 +151,7 @@ class LIRIAURORACOMPOSITOR_EXPORT WaylandOutput : public WaylandObject
void manufacturerChanged();
void modelChanged();
void windowDestroyed();
void platformOutputChanged();

protected:
bool event(QEvent *event) override;
Expand Down
6 changes: 5 additions & 1 deletion src/compositor/compositor_api/aurorawaylandoutput_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ class LIRIAURORACOMPOSITOR_EXPORT WaylandOutputPrivate : public QObjectPrivate,

void handleWindowPixelSizeChanged();

WaylandOutput::Subpixel convertSubpixel(const Aurora::Platform::Output::Subpixel &subpixel);
WaylandOutput::Transform convertTransform(const Aurora::Platform::Output::Transform &transform);
void addModesFromPlatformOutput();

QPointer<WaylandXdgOutputV1> xdgOutput;

protected:
Expand All @@ -105,6 +109,7 @@ class LIRIAURORACOMPOSITOR_EXPORT WaylandOutputPrivate : public QObjectPrivate,
bool sizeFollowsWindow = false;
bool initialized = false;
QSize windowPixelSize;
Aurora::Platform::Output *platformOutput = nullptr;

Q_DISABLE_COPY(WaylandOutputPrivate)

Expand All @@ -115,4 +120,3 @@ class LIRIAURORACOMPOSITOR_EXPORT WaylandOutputPrivate : public QObjectPrivate,
} // namespace Compositor

} // namespace Aurora

10 changes: 9 additions & 1 deletion src/platform/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ liri_add_module(AuroraPlatform
inputmanager.cpp inputmanager.h
keyboarddevice.cpp keyboarddevice.h keyboarddevice_p.h
output.cpp output.h output_p.h
outputsmodel.cpp outputsmodel.h outputsmodel_p.h
pointerdevice.cpp pointerdevice.h
session.cpp session.h
session_noop.cpp session_noop_p.h
Expand All @@ -36,6 +37,13 @@ liri_add_module(AuroraPlatform
PUBLIC_LIBRARIES
Qt6::Core
Qt6::Gui
Qt6::Qml
)

liri_finalize_module(AuroraPlatform)

ecm_add_qml_module(AuroraPlatform
URI Aurora.Platform
VERSION 1.0
GENERATE_PLUGIN_SOURCE
)
ecm_finalize_qml_module(AuroraPlatform)
3 changes: 3 additions & 0 deletions src/platform/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <QRect>
#include <QScreen>
#include <QUuid>
#include <QQmlEngine>

#include <LiriAuroraPlatform/liriauroraplatformglobal.h>

Expand All @@ -21,6 +22,8 @@ class OutputPrivate;
class LIRIAURORAPLATFORM_EXPORT Output : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(PlatformOutput)
QML_UNCREATABLE("Cannot instantiate PlatformOutput")
Q_PROPERTY(QUuid uuid READ uuid CONSTANT)
Q_PROPERTY(QScreen *screen READ screen NOTIFY screenChanged)
Q_PROPERTY(QString name READ name CONSTANT)
Expand Down
87 changes: 87 additions & 0 deletions src/platform/outputsmodel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: 2024 Pier Luigi Fiorini <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "eglfsdeviceintegration_p.h"
#include "outputsmodel.h"
#include "outputsmodel_p.h"

namespace Aurora {

namespace Platform {

/*
* PlatformOutputsModel
*/

OutputsModel::OutputsModel(QObject *parent)
: QAbstractListModel(parent)
, d_ptr(new OutputsModelPrivate(this))
{
Q_D(OutputsModel);

auto *deviceIntegration = auroraDeviceIntegration();
d->outputs = deviceIntegration->outputs();

connect(deviceIntegration, &DeviceIntegration::outputAdded, this, [this, d](Output *output) {
beginInsertRows(QModelIndex(), d->outputs.size(), d->outputs.size());
d->outputs.append(output);
endInsertRows();
});
connect(deviceIntegration, &DeviceIntegration::outputRemoved, this, [this, d](Output *output) {
beginRemoveRows(QModelIndex(), d->outputs.size(), d->outputs.size());
d->outputs.removeOne(output);
endRemoveRows();
});
}

OutputsModel::~OutputsModel()
{
}

QHash<int, QByteArray> OutputsModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[OutputRole] = "output";
return roles;
}

int OutputsModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
Q_D(const OutputsModel);
return d->outputs.size();
}

QVariant OutputsModel::data(const QModelIndex &index, int role) const
{
Q_D(const OutputsModel);

if (index.row() < 0 || index.row() >= d->outputs.size())
return {};

auto *output = d->outputs.at(index.row());
if (!output)
return {};

switch (role) {
case OutputRole:
return QVariant::fromValue(output);
default:
break;
}

return {};
}

/*
* OutputsModelPrivate
*/

OutputsModelPrivate::OutputsModelPrivate(OutputsModel *self)
: q_ptr(self)
{
}

} // namespace Platform

} // namespace Aurora
41 changes: 41 additions & 0 deletions src/platform/outputsmodel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2024 Pier Luigi Fiorini <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-or-later

#pragma once

#include <QAbstractListModel>
#include <QQmlEngine>

#include <LiriAuroraPlatform/liriauroraplatformglobal.h>

namespace Aurora {

namespace Platform {

class OutputsModelPrivate;

class LIRIAURORAPLATFORM_EXPORT OutputsModel : public QAbstractListModel
{
Q_OBJECT
QML_NAMED_ELEMENT(PlatformOutputsModel)
Q_DECLARE_PRIVATE(OutputsModel)
public:
enum OutputRoles {
OutputRole = Qt::UserRole + 1
};

explicit OutputsModel(QObject *parent = nullptr);
~OutputsModel();

QHash<int, QByteArray> roleNames() const override;

int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

private:
QScopedPointer<OutputsModelPrivate> const d_ptr;
};

} // namespace Platform

} // namespace Aurora
Loading

0 comments on commit 3b30883

Please sign in to comment.