Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/helpers/Monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,4 @@ void SMonitor::initSCFrame() {
Debug::log(CRIT, "Failed to get a Screencopy!");
g_pHyprpicker->finish(1);
});
}
}
4 changes: 2 additions & 2 deletions src/helpers/Monitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ struct SMonitor {
SP<CCWlOutput> output = nullptr;
uint32_t wayland_name = 0;
Vector2D size;
int scale;
int32_t scale;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;

bool ready = false;

CLayerSurface* pLS = nullptr;
SP<CCZwlrScreencopyFrameV1> pSCFrame = nullptr;
};
};
241 changes: 129 additions & 112 deletions src/hyprpicker.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
#include "hyprpicker.hpp"
#include "src/debug/Log.hpp"
#include "src/notify/Notify.hpp"
#include <csignal>
#include <cstddef>
#include <cstdio>
#include <format>
#include <hyprutils/math/Vector2D.hpp>
#include <wayland-client-protocol.h>
#include <xkbcommon/xkbcommon-keysyms.h>
#include <xkbcommon/xkbcommon.h>

static void sigHandler(int sig) {
g_pHyprpicker->m_vLayerSurfaces.clear();
Expand All @@ -13,7 +18,7 @@ static void sigHandler(int sig) {
void CHyprpicker::init() {
m_pXKBContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!m_pXKBContext)
Debug::log(ERR, "Failed to create xkb context");
Debug::log(ERR, "Failed to create xkb context, keyboard movement not supported");

m_pWLDisplay = wl_display_connect(nullptr);

Expand Down Expand Up @@ -149,6 +154,116 @@ void CHyprpicker::finish(int code) {
exit(code);
}

void CHyprpicker::outputColor() {

// relative brightness of a color
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
const auto FLUMI = [](const float& c) -> float { return c <= 0.03928 ? c / 12.92 : powf((c + 0.055) / 1.055, 2.4); };

// get the px and print it
const auto MOUSECOORDSABS = m_vLastCoords.floor() / m_pLastSurface->m_pMonitor->size;
const auto CLICKPOS = MOUSECOORDSABS * m_pLastSurface->screenBuffer->pixelSize;

const auto COL = getColorFromPixel(m_pLastSurface, CLICKPOS);

// threshold: (lumi_white + 0.05) / (x + 0.05) == (x + 0.05) / (lumi_black + 0.05)
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
const uint8_t FG = 0.2126 * FLUMI(COL.r / 255.0f) + 0.7152 * FLUMI(COL.g / 255.0f) + 0.0722 * FLUMI(COL.b / 255.0f) > 0.17913 ? 0 : 255;

std::string hexColor = std::format("#{0:02x}{1:02x}{2:02x}", COL.r, COL.g, COL.b);

switch (m_bSelectedOutputMode) {
case OUTPUT_CMYK: {
float c, m, y, k;
COL.getCMYK(c, m, y, k);

std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(c, m, y, k));

if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else
Debug::log(NONE, formattedColor.c_str());

if (m_bAutoCopy)
NClipboard::copy(formattedColor);

if (m_bNotify)
NNotify::send(hexColor, formattedColor);

finish();
break;
}
case OUTPUT_HEX: {
std::string rHex, gHex, bHex;
if (m_bUseLowerCase) {
rHex = std::format("{:02x}", COL.r);
gHex = std::format("{:02x}", COL.g);
bHex = std::format("{:02x}", COL.b);
} else {
rHex = std::format("{:02X}", COL.r);
gHex = std::format("{:02X}", COL.g);
bHex = std::format("{:02X}", COL.b);
}
std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(rHex, gHex, bHex));
if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else
Debug::log(NONE, formattedColor.c_str());

if (m_bAutoCopy)
NClipboard::copy(hexColor);

if (m_bNotify)
NNotify::send(hexColor, hexColor);

finish();
break;
}
case OUTPUT_RGB: {
std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(COL.r, COL.g, COL.b));

if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else
Debug::log(NONE, formattedColor.c_str());

if (m_bAutoCopy)
NClipboard::copy(formattedColor);

if (m_bNotify)
NNotify::send(hexColor, formattedColor);

finish();
break;
}
case OUTPUT_HSL:
case OUTPUT_HSV: {
float h, s, l_or_v;
if (m_bSelectedOutputMode == OUTPUT_HSV)
COL.getHSV(h, s, l_or_v);
else
COL.getHSL(h, s, l_or_v);

std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(h, s, l_or_v));
if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else
Debug::log(NONE, formattedColor.c_str());

if (m_bAutoCopy)
NClipboard::copy(formattedColor);

if (m_bNotify)
NNotify::send(hexColor, formattedColor);

finish();
break;
}
}

finish();
}

void CHyprpicker::recheckACK() {
for (auto& ls : m_vLayerSurfaces) {
if ((ls->wantsACK || ls->wantsReload) && ls->screenBuffer) {
Expand Down Expand Up @@ -606,9 +721,19 @@ void CHyprpicker::initKeyboard() {
m_pKeyboard->setKey([this](CCWlKeyboard* r, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
return;

if (m_pXKBState) {
if (xkb_state_key_get_one_sym(m_pXKBState, key + 8) == XKB_KEY_Escape)
int32_t XKBKey = xkb_state_key_get_one_sym(m_pXKBState, key + 8);
if (XKBKey == XKB_KEY_Right)
m_vLastCoords.x += m_vLastCoords.x < m_pLastSurface->m_pMonitor->size.x;
else if (XKBKey == XKB_KEY_Left)
m_vLastCoords.x -= m_vLastCoords.x > 0;
else if (XKBKey == XKB_KEY_Up)
m_vLastCoords.y -= m_vLastCoords.y > 0;
else if (XKBKey == XKB_KEY_Down)
m_vLastCoords.y += m_vLastCoords.y < m_pLastSurface->m_pMonitor->size.y;
else if (XKBKey == XKB_KEY_Return)
outputColor();
else if (XKBKey == XKB_KEY_Escape)
finish(2);
} else if (key == 1) // Assume keycode 1 is escape
finish(2);
Expand Down Expand Up @@ -654,115 +779,7 @@ void CHyprpicker::initMouse() {

markDirty();
});
m_pPointer->setButton([this](CCWlPointer* r, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) {
// relative brightness of a color
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
const auto FLUMI = [](const float& c) -> float { return c <= 0.03928 ? c / 12.92 : powf((c + 0.055) / 1.055, 2.4); };

// get the px and print it
const auto MOUSECOORDSABS = m_vLastCoords.floor() / m_pLastSurface->m_pMonitor->size;
const auto CLICKPOS = MOUSECOORDSABS * m_pLastSurface->screenBuffer->pixelSize;

const auto COL = getColorFromPixel(m_pLastSurface, CLICKPOS);

// threshold: (lumi_white + 0.05) / (x + 0.05) == (x + 0.05) / (lumi_black + 0.05)
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
const uint8_t FG = 0.2126 * FLUMI(COL.r / 255.0f) + 0.7152 * FLUMI(COL.g / 255.0f) + 0.0722 * FLUMI(COL.b / 255.0f) > 0.17913 ? 0 : 255;

std::string hexColor = std::format("#{0:02x}{1:02x}{2:02x}", COL.r, COL.g, COL.b);

switch (m_bSelectedOutputMode) {
case OUTPUT_CMYK: {
float c, m, y, k;
COL.getCMYK(c, m, y, k);

std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(c, m, y, k));

if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else
Debug::log(NONE, formattedColor.c_str());

if (m_bAutoCopy)
NClipboard::copy(formattedColor);

if (m_bNotify)
NNotify::send(hexColor, formattedColor);

finish();
break;
}
case OUTPUT_HEX: {
std::string rHex, gHex, bHex;
if (m_bUseLowerCase) {
rHex = std::format("{:02x}", COL.r);
gHex = std::format("{:02x}", COL.g);
bHex = std::format("{:02x}", COL.b);
} else {
rHex = std::format("{:02X}", COL.r);
gHex = std::format("{:02X}", COL.g);
bHex = std::format("{:02X}", COL.b);
}
std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(rHex, gHex, bHex));
if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else
Debug::log(NONE, formattedColor.c_str());

if (m_bAutoCopy)
NClipboard::copy(hexColor);

if (m_bNotify)
NNotify::send(hexColor, hexColor);

finish();
break;
}
case OUTPUT_RGB: {
std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(COL.r, COL.g, COL.b));

if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else
Debug::log(NONE, formattedColor.c_str());

if (m_bAutoCopy)
NClipboard::copy(formattedColor);

if (m_bNotify)
NNotify::send(hexColor, formattedColor);

finish();
break;
}
case OUTPUT_HSL:
case OUTPUT_HSV: {
float h, s, l_or_v;
if (m_bSelectedOutputMode == OUTPUT_HSV)
COL.getHSV(h, s, l_or_v);
else
COL.getHSL(h, s, l_or_v);

std::string formattedColor = std::vformat(m_sOutputFormat, std::make_format_args(h, s, l_or_v));
if (m_bFancyOutput)
Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, formattedColor.c_str());
else
Debug::log(NONE, formattedColor.c_str());

if (m_bAutoCopy)
NClipboard::copy(formattedColor);

if (m_bNotify)
NNotify::send(hexColor, formattedColor);

finish();
break;
}
}

finish();
});

m_pPointer->setButton([this](CCWlPointer* r, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) { outputColor(); });
m_pPointer->setAxis([this](CCWlPointer* r, uint32_t time, uint32_t axis, wl_fixed_t value) {
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
return;
Expand Down
1 change: 1 addition & 0 deletions src/hyprpicker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class CHyprpicker {
void markDirty();

void finish(int code = 0);
void outputColor();

CColor getColorFromPixel(CLayerSurface*, Vector2D);

Expand Down