summaryrefslogtreecommitdiff
path: root/src/protocols/GammaControl.cpp
diff options
context:
space:
mode:
authorVaxry <vaxry@vaxry.net>2024-04-22 18:21:03 +0100
committerVaxry <vaxry@vaxry.net>2024-04-22 18:21:03 +0100
commit741c75d907916d760163f910e65186d410e27874 (patch)
treee0170d0418418b20dc9fc5f96bb3b0c3bc9e4c58 /src/protocols/GammaControl.cpp
parentdafc9ed4eb225e87d09cc92273dd390b8a15dbd0 (diff)
gamma-control: move to new impl
Diffstat (limited to 'src/protocols/GammaControl.cpp')
-rw-r--r--src/protocols/GammaControl.cpp177
1 files changed, 177 insertions, 0 deletions
diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp
new file mode 100644
index 00000000..fa7fddd7
--- /dev/null
+++ b/src/protocols/GammaControl.cpp
@@ -0,0 +1,177 @@
+#include "GammaControl.hpp"
+#include <fcntl.h>
+#include <unistd.h>
+#include "../helpers/Monitor.hpp"
+#include "../Compositor.hpp"
+
+CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* output) : resource(resource_) {
+ if (!resource_->resource())
+ return;
+
+ wlr_output* wlrOutput = wlr_output_from_resource(output);
+
+ if (!wlrOutput) {
+ Debug::log(ERR, "[gamma] No wlr_output");
+ resource->sendFailed();
+ return;
+ }
+
+ pMonitor = g_pCompositor->getRealMonitorFromOutput(wlrOutput);
+
+ if (!pMonitor) {
+ Debug::log(ERR, "[gamma] No CMonitor");
+ resource->sendFailed();
+ return;
+ }
+
+ for (auto& g : PROTO::gamma->m_vGammaControllers) {
+ if (g->pMonitor == pMonitor) {
+ resource->sendFailed();
+ return;
+ }
+ }
+
+ gammaSize = wlr_output_get_gamma_size(wlrOutput);
+
+ if (gammaSize <= 0) {
+ Debug::log(ERR, "[gamma] Output {} doesn't support gamma", pMonitor->szName);
+ resource->sendFailed();
+ return;
+ }
+
+ gammaTable.resize(gammaSize * 3);
+
+ resource->setDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); });
+ resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); });
+
+ resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) {
+ Debug::log(LOG, "[gamma] setGamma for {}", pMonitor->szName);
+
+ int fdFlags = fcntl(fd, F_GETFL, 0);
+ if (fdFlags < 0) {
+ Debug::log(ERR, "[gamma] Failed to get fd flags");
+ resource->sendFailed();
+ close(fd);
+ return;
+ }
+
+ if (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) {
+ Debug::log(ERR, "[gamma] Failed to set fd flags");
+ resource->sendFailed();
+ close(fd);
+ return;
+ }
+
+ ssize_t readBytes = pread(fd, gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0);
+ if (readBytes < 0 || (size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) {
+ Debug::log(ERR, "[gamma] Failed to read bytes");
+ close(fd);
+
+ if ((size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) {
+ wl_resource_post_error(gamma->resource(), ZWLR_GAMMA_CONTROL_V1_ERROR_INVALID_GAMMA, "Gamma ramps size mismatch");
+ return;
+ }
+
+ resource->sendFailed();
+ return;
+ }
+
+ gammaTableSet = true;
+ close(fd);
+ applyToMonitor();
+ });
+
+ resource->sendGammaSize(gammaSize);
+
+ listeners.monitorDestroy = pMonitor->events.destroy.registerListener([this](std::any) { this->onMonitorDestroy(); });
+ listeners.monitorDisconnect = pMonitor->events.destroy.registerListener([this](std::any) { this->onMonitorDestroy(); });
+}
+
+CGammaControl::~CGammaControl() {
+ if (!gammaTableSet || !pMonitor)
+ return;
+
+ // reset the LUT if the client dies for whatever reason and doesn't unset the gamma
+ wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
+}
+
+bool CGammaControl::good() {
+ return resource->resource();
+}
+
+void CGammaControl::applyToMonitor() {
+ if (!pMonitor)
+ return; // ??
+
+ Debug::log(LOG, "[gamma] setting to monitor {}", pMonitor->szName);
+
+ if (!gammaTableSet) {
+ wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
+ return;
+ }
+
+ uint16_t* red = &gammaTable.at(0);
+ uint16_t* green = &gammaTable.at(gammaSize);
+ uint16_t* blue = &gammaTable.at(gammaSize * 2);
+
+ wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), gammaSize, red, green, blue);
+
+ if (!pMonitor->state.test()) {
+ Debug::log(LOG, "[gamma] setting to monitor {} failed", pMonitor->szName);
+ wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
+ }
+
+ g_pHyprRenderer->damageMonitor(pMonitor);
+}
+
+CMonitor* CGammaControl::getMonitor() {
+ return pMonitor;
+}
+
+void CGammaControl::onMonitorDestroy() {
+ resource->sendFailed();
+ pMonitor = nullptr;
+}
+
+CGammaControlProtocol::CGammaControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
+ ;
+}
+
+void CGammaControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
+ const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CZwlrGammaControlManagerV1>(client, ver, id)).get();
+ RESOURCE->setOnDestroy([this](CZwlrGammaControlManagerV1* p) { this->onManagerResourceDestroy(p->resource()); });
+
+ RESOURCE->setDestroy([this](CZwlrGammaControlManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
+ RESOURCE->setGetGammaControl([this](CZwlrGammaControlManagerV1* pMgr, uint32_t id, wl_resource* output) { this->onGetGammaControl(pMgr, id, output); });
+}
+
+void CGammaControlProtocol::onManagerResourceDestroy(wl_resource* res) {
+ std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
+}
+
+void CGammaControlProtocol::destroyGammaControl(CGammaControl* gamma) {
+ std::erase_if(m_vGammaControllers, [&](const auto& other) { return other.get() == gamma; });
+}
+
+void CGammaControlProtocol::onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, uint32_t id, wl_resource* output) {
+ const auto CLIENT = wl_resource_get_client(pMgr->resource());
+ const auto RESOURCE =
+ m_vGammaControllers.emplace_back(std::make_unique<CGammaControl>(std::make_shared<CZwlrGammaControlV1>(CLIENT, wl_resource_get_version(pMgr->resource()), id), output))
+ .get();
+
+ if (!RESOURCE->good()) {
+ wl_resource_post_no_memory(pMgr->resource());
+ m_vGammaControllers.pop_back();
+ return;
+ }
+}
+
+void CGammaControlProtocol::applyGammaToState(CMonitor* pMonitor) {
+ for (auto& g : m_vGammaControllers) {
+ if (g->getMonitor() != pMonitor)
+ continue;
+
+ g->applyToMonitor();
+ break;
+ }
+} \ No newline at end of file