diff --git a/README.md b/README.md index c42834f..c65992b 100644 --- a/README.md +++ b/README.md @@ -46,3 +46,4 @@ cmake --install ./build # Caveats "Freezes" your displays when picking the color. + diff --git a/src/clipboard/Clipboard.cpp b/src/clipboard/Clipboard.cpp index 28390df..024653b 100644 --- a/src/clipboard/Clipboard.cpp +++ b/src/clipboard/Clipboard.cpp @@ -1,20 +1,12 @@ #include "Clipboard.hpp" #include "../includes.hpp" +#include +#include +#include -void Clipboard::copy(const char* fmt, ...) { - char buf[CLIPBOARDMESSAGESIZE] = ""; - char* outputStr; +void NClipboard::copy(std::string data) { + Hyprutils::OS::CProcess copy("wl-copy", {data}); - va_list args; - va_start(args, fmt); - vsnprintf(buf, sizeof buf, fmt, args); - va_end(args); - - outputStr = strdup(buf); - - if (fork() == 0) - execlp("wl-copy", "wl-copy", outputStr, NULL); - - free(outputStr); + copy.runAsync(); } diff --git a/src/clipboard/Clipboard.hpp b/src/clipboard/Clipboard.hpp index 1dc2be1..4038cd3 100644 --- a/src/clipboard/Clipboard.hpp +++ b/src/clipboard/Clipboard.hpp @@ -1,7 +1,7 @@ #pragma once -#define CLIPBOARDMESSAGESIZE 24 +#include -namespace Clipboard { - void copy(const char* fmt, ...); -}; \ No newline at end of file +namespace NClipboard { + void copy(std::string data); +}; diff --git a/src/defines.hpp b/src/defines.hpp index 599c418..dbf5438 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -5,6 +5,7 @@ #include "helpers/Monitor.hpp" #include "helpers/Color.hpp" #include "clipboard/Clipboard.hpp" +#include "notify/Notify.hpp" // git stuff #ifndef GIT_COMMIT_HASH diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 8041d83..07f69db 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -1,7 +1,11 @@ #include "hyprpicker.hpp" +#include "src/notify/Notify.hpp" #include +#include +#include +#include -void sigHandler(int sig) { +static void sigHandler(int sig) { g_pHyprpicker->m_vLayerSurfaces.clear(); exit(0); } @@ -242,13 +246,13 @@ void CHyprpicker::convertBuffer(SP pBuffer) { for (int y = 0; y < pBuffer->pixelSize.y; ++y) { for (int x = 0; x < pBuffer->pixelSize.x; ++x) { - struct pixel { + struct SPixel { // little-endian ARGB unsigned char blue; unsigned char green; unsigned char red; unsigned char alpha; - }* px = (struct pixel*)(data + (y * (int)pBuffer->pixelSize.x * 4) + (x * 4)); + }* px = (struct SPixel*)(data + (static_cast(y * (int)pBuffer->pixelSize.x * 4)) + (static_cast(x * 4))); std::swap(px->red, px->blue); } @@ -262,7 +266,7 @@ void CHyprpicker::convertBuffer(SP pBuffer) { for (int y = 0; y < pBuffer->pixelSize.y; ++y) { for (int x = 0; x < pBuffer->pixelSize.x; ++x) { - uint32_t* px = (uint32_t*)(data + (y * (int)pBuffer->pixelSize.x * 4) + (x * 4)); + uint32_t* px = (uint32_t*)(data + (static_cast(y * (int)pBuffer->pixelSize.x * 4)) + (static_cast(x * 4))); // conv to 8 bit uint8_t R = (uint8_t)std::round((255.0 * (((*px) & 0b00000000000000000000001111111111) >> 0) / 1023.0)); @@ -292,19 +296,19 @@ void* CHyprpicker::convert24To32Buffer(SP pBuffer) { case WL_SHM_FORMAT_BGR888: { for (int y = 0; y < pBuffer->pixelSize.y; ++y) { for (int x = 0; x < pBuffer->pixelSize.x; ++x) { - struct pixel3 { + struct SPixel3 { // little-endian RGB unsigned char blue; unsigned char green; unsigned char red; - }* srcPx = (struct pixel3*)(oldBuffer + (y * pBuffer->stride) + (x * 3)); - struct pixel4 { + }* srcPx = (struct SPixel3*)(oldBuffer + (static_cast(y * pBuffer->stride)) + (static_cast(x * 3))); + struct SPixel4 { // little-endian ARGB unsigned char blue; unsigned char green; unsigned char red; unsigned char alpha; - }* dstPx = (struct pixel4*)(newBuffer + (y * newBufferStride) + (x * 4)); + }* dstPx = (struct SPixel4*)(newBuffer + (static_cast(y * newBufferStride)) + (static_cast(x * 4))); *dstPx = {.blue = srcPx->red, .green = srcPx->green, .red = srcPx->blue, .alpha = 0xFF}; } } @@ -312,19 +316,19 @@ void* CHyprpicker::convert24To32Buffer(SP pBuffer) { case WL_SHM_FORMAT_RGB888: { for (int y = 0; y < pBuffer->pixelSize.y; ++y) { for (int x = 0; x < pBuffer->pixelSize.x; ++x) { - struct pixel3 { + struct SPixel3 { // big-endian RGB unsigned char red; unsigned char green; unsigned char blue; - }* srcPx = (struct pixel3*)(oldBuffer + (y * pBuffer->stride) + (x * 3)); - struct pixel4 { + }* srcPx = (struct SPixel3*)(oldBuffer + (y * pBuffer->stride) + (x * 3)); + struct SPixel4 { // big-endian ARGB unsigned char alpha; unsigned char red; unsigned char green; unsigned char blue; - }* dstPx = (struct pixel4*)(newBuffer + (y * newBufferStride) + (x * 4)); + }* dstPx = (struct SPixel4*)(newBuffer + (y * newBufferStride) + (x * 4)); *dstPx = {.alpha = 0xFF, .red = srcPx->red, .green = srcPx->green, .blue = srcPx->blue}; } } @@ -460,7 +464,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { break; }; }; - cairo_set_source_rgba(PCAIRO, 0.0, 0.0, 0.0, 0.5); + cairo_set_source_rgba(PCAIRO, 0.0, 0.0, 0.0, 0.75); double x, y, width = 8 + (11 * previewBuffer.length()), height = 28, radius = 6; @@ -548,12 +552,13 @@ CColor CHyprpicker::getColorFromPixel(CLayerSurface* pLS, Vector2D pix) { return CColor{.r = 0, .g = 0, .b = 0, .a = 0}; void* dataSrc = pLS->screenBuffer->paddedData ? pLS->screenBuffer->paddedData : pLS->screenBuffer->data; - struct pixel { + + struct SPixel { unsigned char blue; unsigned char green; unsigned char red; unsigned char alpha; - }* px = (struct pixel*)((char*)dataSrc + ((ptrdiff_t)pix.y * (int)pLS->screenBuffer->pixelSize.x * 4) + ((ptrdiff_t)pix.x * 4)); + }* px = (struct SPixel*)((char*)dataSrc + ((ptrdiff_t)pix.y * (int)pLS->screenBuffer->pixelSize.x * 4) + ((ptrdiff_t)pix.x * 4)); return CColor{.r = px->red, .g = px->green, .b = px->blue, .a = px->alpha}; } @@ -655,36 +660,41 @@ void CHyprpicker::initMouse() { // 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; + auto toHex = [this](int i) -> std::string { + const char* DS = m_bUseLowerCase ? "0123456789abcdef" : "0123456789ABCDEF"; + + std::string result = ""; + + result += DS[i / 16]; + result += DS[i % 16]; + + return result; + }; + + 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::format("{}% {}% {}% {}%", c, m, y, k); + if (m_bFancyOutput) Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%g%% %g%% %g%% %g%%\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, c, m, y, k); else Debug::log(NONE, "%g%% %g%% %g%% %g%%", c, m, y, k); if (m_bAutoCopy) - Clipboard::copy("%g%% %g%% %g%% %g%%", c, m, y, k); + NClipboard::copy(formattedColor); + + if (m_bNotify) + NNotify::send(hexColor, formattedColor); + finish(); break; } case OUTPUT_HEX: { - auto toHex = [this](int i) -> std::string { - const char* DS = m_bUseLowerCase ? "0123456789abcdef" : "0123456789ABCDEF"; - - std::string result = ""; - - result += DS[i / 16]; - result += DS[i % 16]; - - return result; - }; - - auto hexR = toHex(COL.r); - auto hexG = toHex(COL.g); - auto hexB = toHex(COL.b); - if (m_bFancyOutput) Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im#%s%s%s\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str()); @@ -692,18 +702,28 @@ void CHyprpicker::initMouse() { Debug::log(NONE, "#%s%s%s", toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str()); if (m_bAutoCopy) - Clipboard::copy("#%s%s%s", toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str()); + NClipboard::copy(hexColor); + + if (m_bNotify) + NNotify::send(hexColor, hexColor); + finish(); break; } case OUTPUT_RGB: { + std::string formattedColor = std::format("{} {} {}", COL.r, COL.g, COL.b); + if (m_bFancyOutput) Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%i %i %i\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, COL.r, COL.g, COL.b); else Debug::log(NONE, "%i %i %i", COL.r, COL.g, COL.b); if (m_bAutoCopy) - Clipboard::copy("%i %i %i", COL.r, COL.g, COL.b); + NClipboard::copy(formattedColor); + + if (m_bNotify) + NNotify::send(hexColor, formattedColor); + finish(); break; } @@ -714,13 +734,20 @@ void CHyprpicker::initMouse() { COL.getHSV(h, s, l_or_v); else COL.getHSL(h, s, l_or_v); + + std::string formattedColor = std::format("{} {}% {}%", h, s, l_or_v); + if (m_bFancyOutput) Debug::log(NONE, "\033[38;2;%i;%i;%i;48;2;%i;%i;%im%g %g%% %g%%\033[0m", FG, FG, FG, COL.r, COL.g, COL.b, h, s, l_or_v); else Debug::log(NONE, "%g %g%% %g%%", h, s, l_or_v); if (m_bAutoCopy) - Clipboard::copy("%g %g%% %g%%", h, s, l_or_v); + NClipboard::copy(formattedColor); + + if (m_bNotify) + NNotify::send(hexColor, formattedColor); + finish(); break; } diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index 288b869..0453f61 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -41,6 +41,7 @@ class CHyprpicker { bool m_bFancyOutput = true; bool m_bAutoCopy = false; + bool m_bNotify = false; bool m_bRenderInactive = false; bool m_bNoZoom = false; bool m_bNoFractional = false; diff --git a/src/includes.hpp b/src/includes.hpp index 0b17c60..7c48fc8 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -35,7 +35,9 @@ #include #include +#include using namespace Hyprutils::Memory; +using namespace Hyprutils::OS; #define SP CSharedPointer #define WP CWeakPointer diff --git a/src/main.cpp b/src/main.cpp index 1fa9f9f..0f43b18 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,8 @@ static void help() { std::cout << "Hyprpicker usage: hyprpicker [arg [...]].\n\nArguments:\n" << " -a | --autocopy | Automatically copies the output to the clipboard (requires wl-clipboard)\n" << " -f | --format=fmt | Specifies the output format (cmyk, hex, rgb, hsl, hsv)\n" - << " -n | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" + << " -n | --notify | Sends a desktop notification when a color is picked (requires notify-send and a notification daemon like dunst)\n" + << " -b | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" << " -h | --help | Show this help message\n" << " -r | --render-inactive | Render (freeze) inactive displays\n" << " -z | --no-zoom | Disable the zoom lens\n" @@ -28,7 +29,8 @@ int main(int argc, char** argv, char** envp) { static struct option long_options[] = {{"autocopy", no_argument, nullptr, 'a'}, {"format", required_argument, nullptr, 'f'}, {"help", no_argument, nullptr, 'h'}, - {"no-fancy", no_argument, nullptr, 'n'}, + {"no-fancy", no_argument, nullptr, 'b'}, + {"notify", no_argument, nullptr, 'n'}, {"render-inactive", no_argument, nullptr, 'r'}, {"no-zoom", no_argument, nullptr, 'z'}, {"no-fractional", no_argument, nullptr, 't'}, @@ -39,7 +41,7 @@ int main(int argc, char** argv, char** envp) { {"version", no_argument, nullptr, 'V'}, {nullptr, 0, nullptr, 0}}; - int c = getopt_long(argc, argv, ":f:hnarzqvtdlV", long_options, &option_index); + int c = getopt_long(argc, argv, ":f:hnbarzqvtdlV", long_options, &option_index); if (c == -1) break; @@ -61,7 +63,8 @@ int main(int argc, char** argv, char** envp) { } break; case 'h': help(); exit(0); - case 'n': g_pHyprpicker->m_bFancyOutput = false; break; + case 'b': g_pHyprpicker->m_bFancyOutput = false; break; + case 'n': g_pHyprpicker->m_bNotify = true; break; case 'a': g_pHyprpicker->m_bAutoCopy = true; break; case 'r': g_pHyprpicker->m_bRenderInactive = true; break; case 'z': g_pHyprpicker->m_bNoZoom = true; break; diff --git a/src/notify/Notify.cpp b/src/notify/Notify.cpp new file mode 100644 index 0000000..5379afa --- /dev/null +++ b/src/notify/Notify.cpp @@ -0,0 +1,19 @@ +#include "Notify.hpp" + +#include "../includes.hpp" +#include +#include +#include +#include +#include +#include + +#include + +void NNotify::send(std::string hexColor, std::string formattedColor) { + std::string notifyBody = std::format("Selected color: {}", hexColor, formattedColor); + + Hyprutils::OS::CProcess notify("notify-send", {"-t", "5000", "-i", "color-select-symbolic", "Color Picker", notifyBody}); + + notify.runAsync(); +} diff --git a/src/notify/Notify.hpp b/src/notify/Notify.hpp new file mode 100644 index 0000000..1cd09f0 --- /dev/null +++ b/src/notify/Notify.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +namespace NNotify { + void send(std::string hexColor, std::string formattedColor); +}