mirror of
https://github.com/theCheeseboard/libtdesktopenvironment.git
synced 2025-01-22 10:22:02 -05:00
Implement gamma ramp adjustment
This commit is contained in:
parent
bd03fe54cc
commit
552760db8a
10 changed files with 259 additions and 10 deletions
|
@ -28,25 +28,29 @@ function(tdesktopenvironment_register_wayland_protocol_extension target)
|
|||
foreach(_file ${REGISTER_WAYLAND_PROTOCOL_EXTENSIONS_FILES})
|
||||
get_filename_component(_basename ${_file} NAME_WE)
|
||||
|
||||
if(NOT EXISTS ${_file})
|
||||
set(_file ${CMAKE_CURRENT_SOURCE_DIR}/${_file})
|
||||
endif()
|
||||
|
||||
# Wayland scanner
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.h"
|
||||
COMMAND ${WAYLAND_SCANNER} client-header ${CMAKE_CURRENT_SOURCE_DIR}/${_file} "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.h"
|
||||
COMMAND ${WAYLAND_SCANNER} client-header ${_file} "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.h"
|
||||
DEPENDS ${_file}
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.c"
|
||||
COMMAND ${WAYLAND_SCANNER} public-code ${CMAKE_CURRENT_SOURCE_DIR}/${_file} "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.c"
|
||||
COMMAND ${WAYLAND_SCANNER} public-code ${_file} "${CMAKE_CURRENT_BINARY_DIR}/wayland-${_basename}-client-protocol.c"
|
||||
DEPENDS ${_file}
|
||||
VERBATIM)
|
||||
|
||||
# Qt Wayland scanner
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.h"
|
||||
COMMAND ${QT_WAYLAND_SCANNER} client-header ${CMAKE_CURRENT_SOURCE_DIR}/${_file} > "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.h"
|
||||
COMMAND ${QT_WAYLAND_SCANNER} client-header ${_file} > "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.h"
|
||||
DEPENDS ${_file}
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.cpp"
|
||||
COMMAND ${QT_WAYLAND_SCANNER} client-code ${CMAKE_CURRENT_SOURCE_DIR}/${_file} > "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.cpp"
|
||||
COMMAND ${QT_WAYLAND_SCANNER} client-code ${_file} > "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${_basename}.cpp"
|
||||
DEPENDS ${_file}
|
||||
VERBATIM)
|
||||
|
||||
|
@ -65,4 +69,4 @@ endfunction()
|
|||
|
||||
add_subdirectory(wayland-layer-shell)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(plugins)
|
||||
add_subdirectory(plugins)
|
||||
|
|
|
@ -17,6 +17,8 @@ else()
|
|||
Screens/waylandmode.cpp
|
||||
Screens/waylandscreen.cpp
|
||||
Screens/waylandscreenbackend.cpp
|
||||
Screens/waylandgammacontrol.cpp
|
||||
Screens/waylandoutput.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
|
@ -31,6 +33,8 @@ else()
|
|||
Screens/waylandmode.h
|
||||
Screens/waylandscreen.h
|
||||
Screens/waylandscreenbackend.h
|
||||
Screens/waylandgammacontrol.h
|
||||
Screens/waylandoutput.h
|
||||
)
|
||||
|
||||
set(PLUGIN_NAME wayland)
|
||||
|
@ -47,6 +51,7 @@ target_sources(plugin-${PLUGIN_NAME} PRIVATE ${SOURCES} ${HEADERS})
|
|||
wayland-protocols/tdesktopenvironment-protocols/tdesktopenvironment-accessibility-v1.xml
|
||||
wayland-protocols/wlr-protocols/unstable/wlr-output-management-unstable-v1.xml
|
||||
wayland-protocols/wlr-protocols/unstable/wlr-gamma-control-unstable-v1.xml
|
||||
${CMAKE_INSTALL_FULL_DATADIR}/wayland/wayland.xml
|
||||
)
|
||||
install(DIRECTORY wayland-protocols/tdesktopenvironment-protocols
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/libtdesktopenvironment/wayland-protocols
|
||||
|
|
62
plugins/wayland/Screens/waylandgammacontrol.cpp
Normal file
62
plugins/wayland/Screens/waylandgammacontrol.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "waylandgammacontrol.h"
|
||||
|
||||
#include "twaylandregistry.h"
|
||||
#include "waylandoutput.h"
|
||||
#include <tlogger.h>
|
||||
|
||||
struct WaylandGammaControlPrivate {
|
||||
QString name;
|
||||
QString description;
|
||||
|
||||
tWaylandRegistry registry;
|
||||
QSharedPointer<wl_output> output;
|
||||
|
||||
quint32 gammaSize;
|
||||
};
|
||||
|
||||
WaylandGammaControl::WaylandGammaControl(QString name, QString description, QtWayland::zwlr_gamma_control_manager_v1* gammaControlManager, QObject* parent) :
|
||||
QObject{parent} {
|
||||
d = new WaylandGammaControlPrivate();
|
||||
d->name = name;
|
||||
d->description = description;
|
||||
|
||||
for (const auto& wlOutput : d->registry.interfaces<wl_output>(&wl_output_interface, 4)) {
|
||||
WaylandOutput output(wlOutput.data());
|
||||
tDebug("WaylandGammaControl") << "Found output name: " << output.name();
|
||||
if (output.name() == name && output.description() == description) {
|
||||
// We found the correct output
|
||||
tDebug("WaylandGammaControl") << "Found the output for a gamma control";
|
||||
d->output = wlOutput;
|
||||
auto gammaControl = gammaControlManager->get_gamma_control(wlOutput.data());
|
||||
this->QtWayland::zwlr_gamma_control_v1::init(gammaControl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WaylandGammaControl::~WaylandGammaControl() {
|
||||
delete d;
|
||||
}
|
||||
|
||||
quint32 WaylandGammaControl::rampSize() {
|
||||
return d->gammaSize;
|
||||
}
|
||||
|
||||
bool WaylandGammaControl::isReady() {
|
||||
return this->isInitialized();
|
||||
}
|
||||
|
||||
void WaylandGammaControl::setGamma(int32_t fd) {
|
||||
this->set_gamma(fd);
|
||||
|
||||
auto display = reinterpret_cast<wl_display*>(qApp->platformNativeInterface()->nativeResourceForIntegration("display"));
|
||||
wl_display_roundtrip(display);
|
||||
}
|
||||
|
||||
void WaylandGammaControl::zwlr_gamma_control_v1_gamma_size(uint32_t size) {
|
||||
d->gammaSize = size;
|
||||
}
|
||||
|
||||
void WaylandGammaControl::zwlr_gamma_control_v1_failed() {
|
||||
tWarn("WaylandGammaControl") << "Setting gamma ramps failed for display " << d->name;
|
||||
}
|
31
plugins/wayland/Screens/waylandgammacontrol.h
Normal file
31
plugins/wayland/Screens/waylandgammacontrol.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef WAYLANDGAMMACONTROL_H
|
||||
#define WAYLANDGAMMACONTROL_H
|
||||
|
||||
#include "qwayland-wlr-gamma-control-unstable-v1.h"
|
||||
#include <QObject>
|
||||
|
||||
struct WaylandGammaControlPrivate;
|
||||
class WaylandGammaControl : public QObject,
|
||||
private QtWayland::zwlr_gamma_control_v1 {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WaylandGammaControl(QString name, QString description, QtWayland::zwlr_gamma_control_manager_v1* gammaControlManager, QObject* parent = nullptr);
|
||||
~WaylandGammaControl();
|
||||
|
||||
quint32 rampSize();
|
||||
|
||||
bool isReady();
|
||||
void setGamma(int32_t fd);
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
WaylandGammaControlPrivate* d;
|
||||
|
||||
// zwlr_gamma_control_v1 interface
|
||||
protected:
|
||||
void zwlr_gamma_control_v1_gamma_size(uint32_t size);
|
||||
void zwlr_gamma_control_v1_failed();
|
||||
};
|
||||
|
||||
#endif // WAYLANDGAMMACONTROL_H
|
42
plugins/wayland/Screens/waylandoutput.cpp
Normal file
42
plugins/wayland/Screens/waylandoutput.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "waylandoutput.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
#include <tlogger.h>
|
||||
|
||||
struct WaylandOutputPrivate {
|
||||
QString name;
|
||||
QString description;
|
||||
};
|
||||
|
||||
WaylandOutput::WaylandOutput(::wl_output* output, QObject* parent) :
|
||||
QObject{parent}, QtWayland::wl_output(output) {
|
||||
d = new WaylandOutputPrivate();
|
||||
|
||||
auto display = reinterpret_cast<wl_display*>(qApp->platformNativeInterface()->nativeResourceForIntegration("display"));
|
||||
wl_display_roundtrip(display);
|
||||
}
|
||||
|
||||
WaylandOutput::~WaylandOutput() {
|
||||
delete d;
|
||||
}
|
||||
|
||||
QString WaylandOutput::name() {
|
||||
return d->name;
|
||||
}
|
||||
|
||||
QString WaylandOutput::description() {
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void WaylandOutput::output_name(const QString& name) {
|
||||
d->name = name;
|
||||
}
|
||||
|
||||
void WaylandOutput::output_description(const QString& description) {
|
||||
d->description = description;
|
||||
}
|
||||
|
||||
void WaylandOutput::output_done() {
|
||||
}
|
30
plugins/wayland/Screens/waylandoutput.h
Normal file
30
plugins/wayland/Screens/waylandoutput.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef WAYLANDOUTPUT_H
|
||||
#define WAYLANDOUTPUT_H
|
||||
|
||||
#include "qwayland-wayland.h"
|
||||
#include <QObject>
|
||||
|
||||
struct WaylandOutputPrivate;
|
||||
class WaylandOutput : public QObject,
|
||||
public QtWayland::wl_output {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WaylandOutput(::wl_output* output, QObject* parent = nullptr);
|
||||
~WaylandOutput();
|
||||
|
||||
QString name();
|
||||
QString description();
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
WaylandOutputPrivate* d;
|
||||
|
||||
// wl_output interface
|
||||
protected:
|
||||
void output_name(const QString& name);
|
||||
void output_description(const QString& description);
|
||||
void output_done();
|
||||
};
|
||||
|
||||
#endif // WAYLANDOUTPUT_H
|
|
@ -20,10 +20,19 @@
|
|||
#include "waylandscreen.h"
|
||||
|
||||
#include "Screens/screendaemon.h"
|
||||
#include "waylandgammacontrol.h"
|
||||
#include "waylandmode.h"
|
||||
#include "waylandscreenbackend.h"
|
||||
#include <QApplication>
|
||||
#include <QMap>
|
||||
#include <tlogger.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/memfd.h>
|
||||
|
||||
struct WaylandScreenPrivate {
|
||||
WaylandScreenBackend* backend;
|
||||
|
@ -43,6 +52,8 @@ struct WaylandScreenPrivate {
|
|||
bool initialPowered;
|
||||
int initialMode;
|
||||
QPoint initialPoisition;
|
||||
|
||||
QMap<QString, SystemScreen::GammaRamps> gammaRamps;
|
||||
};
|
||||
|
||||
WaylandScreen::WaylandScreen(::zwlr_output_head_v1* head, WaylandScreenBackend* backend) :
|
||||
|
@ -76,6 +87,50 @@ void WaylandScreen::normaliseScreens() {
|
|||
}
|
||||
}
|
||||
|
||||
void WaylandScreen::updateGammaRamps() {
|
||||
WaylandGammaControl gammaControl(d->name, d->description, d->backend);
|
||||
if (!gammaControl.isReady()) {
|
||||
tWarn("WaylandScreen") << "Unable to set gamma ramps for " << d->name << " because the wlr_gamma_control object could not be initialised";
|
||||
return;
|
||||
}
|
||||
|
||||
GammaRamps ramps;
|
||||
if (d->gammaRamps.empty()) {
|
||||
// Reset the gamma
|
||||
ramps.red = 1;
|
||||
ramps.green = 1;
|
||||
ramps.blue = 1;
|
||||
} else {
|
||||
// Interpolate all the gamma values
|
||||
auto allRamps = d->gammaRamps.values();
|
||||
ramps = allRamps.front();
|
||||
for (auto i = std::next(allRamps.begin()); i != allRamps.end(); i++) {
|
||||
ramps.red *= i->red;
|
||||
ramps.green *= i->green;
|
||||
ramps.blue *= i->blue;
|
||||
}
|
||||
}
|
||||
|
||||
int num_channels = 3, num_entries = gammaControl.rampSize();
|
||||
|
||||
// Creates an unnamed, temporary file in memory
|
||||
int fd = memfd_create("gamma-ramp", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
ftruncate(fd, num_channels * num_entries * sizeof(uint16_t));
|
||||
|
||||
uint16_t* table = static_cast<uint16_t*>(mmap(NULL, num_channels * num_entries * sizeof(uint16_t), PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
|
||||
for (int i = 0; i < num_entries; i++) {
|
||||
double factor = static_cast<double>(UINT16_MAX + 1) * i / num_entries;
|
||||
table[i] = table[i + num_entries] = table[i + num_entries * 2] = static_cast<uint16_t>(factor * ramps.red + 0.5);
|
||||
}
|
||||
|
||||
gammaControl.setGamma(fd);
|
||||
|
||||
// Clean up
|
||||
munmap(table, num_channels * num_entries * sizeof(uint16_t));
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void WaylandScreen::zwlr_output_head_v1_name(const QString& name) {
|
||||
d->name = name;
|
||||
}
|
||||
|
@ -150,9 +205,13 @@ void WaylandScreen::setScreenBrightness(double screenBrightness) {
|
|||
}
|
||||
|
||||
void WaylandScreen::adjustGammaRamps(QString adjustmentName, GammaRamps ramps) {
|
||||
d->gammaRamps.insert(adjustmentName, ramps);
|
||||
updateGammaRamps();
|
||||
}
|
||||
|
||||
void WaylandScreen::removeGammaRamps(QString adjustmentName) {
|
||||
d->gammaRamps.remove(adjustmentName);
|
||||
updateGammaRamps();
|
||||
}
|
||||
|
||||
bool WaylandScreen::powered() const {
|
||||
|
|
|
@ -40,6 +40,7 @@ class WaylandScreen : public SystemScreen,
|
|||
WaylandScreenPrivate* d;
|
||||
|
||||
void normaliseScreens();
|
||||
void updateGammaRamps();
|
||||
|
||||
// zwlr_output_head_v1 interface
|
||||
protected:
|
||||
|
|
|
@ -45,7 +45,7 @@ struct WaylandBackendPrivate {
|
|||
|
||||
tWaylandRegistry registry;
|
||||
wl_display* display;
|
||||
wl_seat* seat;
|
||||
QSharedPointer<wl_seat> seat;
|
||||
|
||||
quint64 nextKeygrabId = 0;
|
||||
QMap<quint64, quint64> extKeygrab;
|
||||
|
@ -100,7 +100,7 @@ wl_display* WaylandBackend::display() {
|
|||
}
|
||||
|
||||
wl_seat* WaylandBackend::seat() {
|
||||
return d->seat;
|
||||
return d->seat.data();
|
||||
}
|
||||
|
||||
void WaylandBackend::viewAdded(uint viewId) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define TWAYLANDREGISTRY_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCoroGenerator>
|
||||
#include <QList>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
|
@ -50,20 +51,31 @@ class tWaylandRegistry {
|
|||
return false;
|
||||
}
|
||||
|
||||
wl_seat* seat() {
|
||||
QSharedPointer<wl_seat> seat() {
|
||||
return this->bind<wl_seat>(&wl_seat_interface, 1);
|
||||
}
|
||||
|
||||
template<typename T> T* bind(const wl_interface* interface, quint32 version) {
|
||||
template<typename T> QSharedPointer<T> bind(const wl_interface* interface, quint32 version) {
|
||||
auto interfaceName = QString::fromLocal8Bit(interface->name);
|
||||
for (const auto& item : this->items) {
|
||||
if (item.interface == interfaceName) {
|
||||
return static_cast<T*>(wl_registry_bind(item.registry, item.name, interface, std::min(version, static_cast<quint32>(1))));
|
||||
auto bound = static_cast<T*>(wl_registry_bind(item.registry, item.name, interface, version));
|
||||
return QSharedPointer<T>(bound, &tWaylandRegistry::resourceDeleter<T>);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T> QCoro::Generator<QSharedPointer<T>> interfaces(const wl_interface* interface, quint32 version) {
|
||||
auto interfaceName = QString::fromLocal8Bit(interface->name);
|
||||
for (const auto& item : this->items) {
|
||||
if (item.interface == interfaceName) {
|
||||
auto bound = static_cast<T*>(wl_registry_bind(item.registry, item.name, interface, version));
|
||||
co_yield QSharedPointer<T>(bound, &tWaylandRegistry::resourceDeleter<T>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct RegistryItem {
|
||||
wl_registry* registry;
|
||||
|
@ -74,6 +86,9 @@ class tWaylandRegistry {
|
|||
|
||||
QList<RegistryItem> items;
|
||||
wl_registry* registry;
|
||||
|
||||
template<typename T> static void resourceDeleter(T* obj) {
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TWAYLANDREGISTRY_H
|
||||
|
|
Loading…
Reference in a new issue