...
 
Commits (16)
......@@ -17,7 +17,7 @@ Message lint:
rules:
- if: $CI_MERGE_REQUEST_IID
when: always
- if: '$CI_COMMIT_BRANCH == "master"'
- if: '$CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH =~ /^Plasma\// || $CI_COMMIT_TAG'
when: never
- when: always
variables:
......@@ -46,16 +46,16 @@ clang-format:
.common-master: &common-master
image: ${IMAGE_BASE}-master:latest
rules:
- if: '$CI_COMMIT_BRANCH =~ /^Plasma\//'
- if: '$CI_COMMIT_BRANCH =~ /^Plasma\// || $CI_COMMIT_TAG'
when: never
- when: on_success
.common-stable: &common-stable
image: ${IMAGE_BASE}-stable:latest
rules:
- if: '$CI_COMMIT_BRANCH !~ /^Plasma\//'
when: never
- when: on_success
- if: '$CI_COMMIT_BRANCH =~ /^Plasma\// || $CI_COMMIT_TAG'
when: on_success
- when: never
.common-build: &common-build
......
# Changelog
All notable changes to Disman will be documented in this file.
## [0.520.0](https://gitlab.com/kwinft/disman/compare/[email protected]@0.520.0) (2020-10-13)
### Features
* **lib:** improve backend manager logging ([bc760c4](https://gitlab.com/kwinft/disman/commit/bc760c40720fd97a3ecac6a28cf92451a182883a))
### Bug Fixes
* **lib:** on backend selection check that Wayland socket exists ([61a3a20](https://gitlab.com/kwinft/disman/commit/61a3a20b25c490b3995ce2da2b077390590c3af3))
* **lib:** prefer XDG_SESSION_TYPE for backend selection ([fd89b72](https://gitlab.com/kwinft/disman/commit/fd89b721ed46348d819ce3aebf9426f19e249be2))
* replace new/delete with unique_ptr ([5e7423b](https://gitlab.com/kwinft/disman/commit/5e7423b08df829c0c3f7f9c052e68578774f74aa))
* **wayland:** capture variable by value ([1306f1d](https://gitlab.com/kwinft/disman/commit/1306f1d73a65d2096eb6bc80628c6532ca285075))
## [0.520.0-beta.1](https://gitlab.com/kwinft/disman/compare/[email protected]@0.520.0-beta.1) (2020-10-02)
### Bug Fixes
* write primary property to config control file ([43d800c](https://gitlab.com/kwinft/disman/commit/43d800c1bd46cec076092f29fa22d2fc981d15db))
* **wayland:** add return to transform getters ([f6622f4](https://gitlab.com/kwinft/disman/commit/f6622f4d025fa9e8929b3bd143b12b590dbb0685))
* **wayland:** check null mode in wlroots backend ([e858f9a](https://gitlab.com/kwinft/disman/commit/e858f9a11ebc2d87ea55a8d6750b0d7267efe1de))
* **wayland:** omit sending any other data on disabling wlr heads ([61a06a8](https://gitlab.com/kwinft/disman/commit/61a06a89530c42224b2f03126c65872168cd082a))
* **wayland:** retry on cancelled wlroots config ([f94b33a](https://gitlab.com/kwinft/disman/commit/f94b33a1c293fedfc81e82679d571c9ff4876ce5))
## [0.520.0-beta.0](https://gitlab.com/kwinft/disman/compare/[email protected]@0.520.0-beta.0) (2020-09-25)
......
cmake_minimum_required(VERSION 3.13)
project(Disman)
set(PROJECT_VERSION "0.519.90")
set(PROJECT_VERSION "0.520.0")
set(PROJECT_VERSION_MAJOR "0")
set(QT_MIN_VERSION "5.14.0")
......
......@@ -69,6 +69,12 @@ public:
output->set_retention(convert_int_to_retention(retention));
output->set_enabled(get_value(output, "enabled", true, nullptr));
if (config->supported_features().testFlag(Disman::Config::Feature::PrimaryDisplay)) {
if (get_value(output, "primary", false, nullptr)) {
config->set_primary_output(output);
}
}
output->set_position(
get_value(output, "pos", QPointF(0, 0), nullptr, std::function{get_pos}));
get_replication_source(output, outputs);
......@@ -124,6 +130,11 @@ public:
set_value(output, "retention", static_cast<int>(output->retention()), nullptr);
set_value(output, "enabled", output->enabled(), nullptr);
if (config->supported_features().testFlag(Disman::Config::Feature::PrimaryDisplay)) {
set_value(output, "primary", config->primary_output().get() == output.get(), filer);
}
set_replication_source(output, config);
set_value(output, "pos", output->position(), nullptr, std::function{set_pos});
......
......@@ -53,6 +53,7 @@ Wl::OutputDevice::Transform toKWaylandTransform(const Output::Rotation rotation)
}
}
assert(false);
return Wl::OutputDevice::Transform::Normal;
}
KWaylandOutput::KWaylandOutput(quint32 id, QObject* parent)
......@@ -148,8 +149,7 @@ void KWaylandOutput::updateDismanOutput(OutputPtr& output)
} else {
output->set_mode(current_mode);
output->set_resolution(current_mode->size());
auto success = output->set_refresh_rate(current_mode->refresh());
if (!success) {
if (!output->set_refresh_rate(current_mode->refresh())) {
qCWarning(DISMAN_WAYLAND) << "Failed setting the current mode:" << current_mode;
}
}
......
......@@ -54,6 +54,7 @@ Wl::OutputDeviceV1::Transform toWraplandTransform(const Output::Rotation rotatio
}
}
assert(false);
return Wl::OutputDeviceV1::Transform::Normal;
}
KwinftOutput::KwinftOutput(quint32 id, QObject* parent)
......@@ -151,8 +152,7 @@ void KwinftOutput::updateDismanOutput(OutputPtr& output)
} else {
output->set_mode(current_mode);
output->set_resolution(current_mode->size());
auto success = output->set_refresh_rate(current_mode->refresh());
if (!success) {
if (!output->set_refresh_rate(current_mode->refresh())) {
qCWarning(DISMAN_WAYLAND) << "Failed setting the current mode:" << current_mode;
}
}
......
......@@ -217,6 +217,11 @@ void WlrootsInterface::tryPendingConfig()
}
bool WlrootsInterface::applyConfig(const Disman::ConfigPtr& newConfig)
{
return apply_config_impl(newConfig, false);
}
bool WlrootsInterface::apply_config_impl(const Disman::ConfigPtr& newConfig, bool force)
{
using namespace Wrapland::Client;
......@@ -239,7 +244,7 @@ bool WlrootsInterface::applyConfig(const Disman::ConfigPtr& newConfig)
changed |= m_outputMap[output->id()]->setWlConfig(wlConfig, output);
}
if (!changed) {
if (!changed && !force) {
qCDebug(DISMAN_WAYLAND)
<< "New config equals compositor's current data. Aborting apply request.";
return false;
......@@ -262,14 +267,14 @@ bool WlrootsInterface::applyConfig(const Disman::ConfigPtr& newConfig)
Q_EMIT config_changed();
tryPendingConfig();
});
connect(wlConfig, &WlrOutputConfigurationV1::cancelled, this, [this, wlConfig] {
// This should never be received since we apply the new config directly. But in case we just
// do the same as on failed.
qCWarning(DISMAN_WAYLAND) << "Applying config failed.";
connect(wlConfig, &WlrOutputConfigurationV1::cancelled, this, [this, newConfig, wlConfig] {
// Can occur if serials were not in sync because of some simultaneous change server-side.
// We try to apply the current config again as we should have received a done event now.
wlConfig->deleteLater();
unblockSignals();
Q_EMIT config_changed();
tryPendingConfig();
auto cfg = m_dismanPendingConfig ? m_dismanPendingConfig : newConfig;
m_dismanPendingConfig = nullptr;
apply_config_impl(cfg, true);
});
blockSignals();
......
......@@ -73,6 +73,8 @@ protected:
private:
void setupRegistry();
void addHead(Wrapland::Client::WlrOutputHeadV1* head);
bool apply_config_impl(const Disman::ConfigPtr& newConfig, bool force);
void tryPendingConfig();
Wrapland::Client::ConnectionThread* m_connection;
......
......@@ -52,6 +52,7 @@ Wl::WlrOutputHeadV1::Transform toWraplandTransform(const Output::Rotation rotati
}
}
assert(false);
return Wl::WlrOutputHeadV1::Transform::Normal;
}
WlrootsOutput::WlrootsOutput(quint32 id,
......@@ -60,12 +61,12 @@ WlrootsOutput::WlrootsOutput(quint32 id,
: WaylandOutput(id, parent)
, m_head(head)
{
connect(m_head, &Wl::WlrOutputHeadV1::changed, this, &WlrootsOutput::changed);
connect(m_head, &Wl::WlrOutputHeadV1::removed, this, &WlrootsOutput::removed);
auto manager = parent->outputManager();
connect(manager, &Wl::WlrOutputManagerV1::done, this, [this, manager]() {
disconnect(manager, &Wl::WlrOutputManagerV1::done, this, nullptr);
connect(m_head, &Wl::WlrOutputHeadV1::changed, this, &WlrootsOutput::changed);
Q_EMIT dataReceived();
});
}
......@@ -86,7 +87,11 @@ bool portraitMode(Wrapland::Client::WlrOutputHeadV1* head)
QRectF WlrootsOutput::geometry() const
{
auto modeSize = m_head->currentMode()->size();
auto const current_mode = m_head->currentMode();
if (!current_mode) {
return QRectF();
}
auto modeSize = current_mode->size();
// Rotate and scale.
if (portraitMode(m_head)) {
......@@ -119,7 +124,7 @@ void WlrootsOutput::updateDismanOutput(OutputPtr& output)
output->set_hash(hash().toStdString());
output->set_physical_size(m_head->physicalSize());
output->set_position(m_head->position());
output->set_rotation(s_rotationMap.at(m_head->transform()));
output->set_rotation(toDismanRotation(m_head->transform()));
ModeMap modeList;
std::vector<std::string> preferredModeIds;
......@@ -159,16 +164,19 @@ void WlrootsOutput::updateDismanOutput(OutputPtr& output)
output->set_preferred_modes(preferredModeIds);
output->set_modes(modeList);
if (!current_mode) {
qCWarning(DISMAN_WAYLAND) << "Could not find the current mode in:";
for (auto const& [key, mode] : modeList) {
qCWarning(DISMAN_WAYLAND) << " " << mode;
if (current_head_mode) {
if (!current_mode) {
qCWarning(DISMAN_WAYLAND) << "Could not find the current mode in:";
for (auto const& [key, mode] : modeList) {
qCWarning(DISMAN_WAYLAND) << " " << mode;
}
} else {
output->set_mode(current_mode);
output->set_resolution(current_mode->size());
if (!output->set_refresh_rate(current_mode->refresh())) {
qCWarning(DISMAN_WAYLAND) << "Failed setting the current mode:" << current_mode;
}
}
} else {
output->set_mode(current_mode);
output->set_resolution(current_mode->size());
auto success = output->set_refresh_rate(current_mode->refresh());
assert(success);
}
output->set_scale(m_head->scale());
......@@ -188,6 +196,11 @@ bool WlrootsOutput::setWlConfig(Wl::WlrOutputConfigurationV1* wlConfig,
// In any case set the enabled state to initialize the output's native handle.
wlConfig->setEnabled(m_head, output->enabled());
if (!output->enabled()) {
// A disabled head can not be configured in any way.
return changed;
}
// position
if (m_head->position() != output->position()) {
changed = true;
......
......@@ -200,7 +200,7 @@ void WaylandBackend::queryInterface(KPluginMetaData* plugin)
pending.thread = new QThread();
m_pendingInterfaces.push_back(pending);
connect(pending.interface, &WaylandInterface::connectionFailed, this, [this, &pending] {
connect(pending.interface, &WaylandInterface::connectionFailed, this, [this, pending] {
qCWarning(DISMAN_WAYLAND) << "Backend" << pending.name << "failed.";
rejectInterface(pending);
m_pendingInterfaces.erase(
......
......@@ -147,15 +147,44 @@ QFileInfo BackendManager::preferred_backend(std::string const& pre_select)
return env_select;
}
if (!qgetenv("WAYLAND_DISPLAY").isEmpty()) {
// If XDG_SESSION_TYPE is defined and indicates a certain windowing system we prefer
// that variable, since it likely reflects correctly the current session setup.
auto const session_type = qgetenv("XDG_SESSION_TYPE");
if (session_type == "wayland") {
return "wayland";
}
if (session_type == "x11") {
return "randr";
}
if (auto display = qgetenv("WAYLAND_DISPLAY"); !display.isEmpty()) {
auto dsp_str = QString::fromLatin1(display);
auto socket_exists = [&dsp_str] {
if (QDir::isAbsolutePath(dsp_str)) {
return QFile(dsp_str).exists();
}
auto const locations
= QStandardPaths::standardLocations(QStandardPaths::RuntimeLocation);
for (auto const dir : locations) {
if (QFileInfo(QDir(dir), dsp_str).exists()) {
return true;
}
}
return false;
};
if (socket_exists()) {
return "wayland";
}
}
if (!qgetenv("DISPLAY").isEmpty()) {
return "randr";
}
return "qscreen";
};
auto const select = get_selection();
qCDebug(DISMAN) << "Selection for preferred backend:" << select.c_str();
QFileInfo fallback;
for (auto const& file_info : list_backends()) {
......@@ -195,6 +224,8 @@ Disman::Backend* BackendManager::load_backend_plugin(QPluginLoader* loader,
{
const auto finfo = preferred_backend(name.toStdString());
loader->setFileName(finfo.filePath());
qCDebug(DISMAN) << "Loading backend plugin:" << finfo.filePath();
QObject* instance = loader->instance();
if (!instance) {
qCDebug(DISMAN) << loader->errorString();
......@@ -209,10 +240,10 @@ Disman::Backend* BackendManager::load_backend_plugin(QPluginLoader* loader,
delete backend;
return nullptr;
}
// qCDebug(DISMAN) << "Loaded" << backend->name() << "backend";
qCDebug(DISMAN) << "Loaded successfully backend:" << backend->name();
return backend;
} else {
qCDebug(DISMAN) << finfo.fileName() << "does not provide valid Disman backend";
qCWarning(DISMAN) << finfo.fileName() << "does not provide a valid Disman backend.";
}
return nullptr;
......
......@@ -27,6 +27,8 @@ qt5_add_dbus_adaptor(backendlauncher_SRCS
add_executable(disman_backend_launcher ${backendlauncher_SRCS})
target_compile_features(disman_backend_launcher PRIVATE cxx_std_17)
target_link_libraries(disman_backend_launcher
Disman::Disman
Qt5::Core
......
......@@ -24,6 +24,8 @@
#include "disman_backend_launcher_debug.h"
#include "log.h"
#include <memory>
int main(int argc, char** argv)
{
Disman::Log::instance();
......@@ -41,16 +43,15 @@ int main(int argc, char** argv)
return -1;
}
BackendLoader* loader = new BackendLoader;
// The backend must be destroyed and unloaded while the QApplication object
// and its XCB connection still exist. This is guaranteed by the fact that
// local variables are destructed in the reverse order of construction.
auto loader = std::make_unique<BackendLoader>();
if (!loader->init()) {
return -2;
}
const int ret = app.exec();
// Make sure the backend is destroyed and unloaded before we return (i.e.
// as long as QApplication object and it's XCB connection still exist
delete loader;
return ret;
}