Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package hyprpicker for openSUSE:Factory checked in at 2026-04-04 19:05:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/hyprpicker (Old) and /work/SRC/openSUSE:Factory/.hyprpicker.new.21863 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "hyprpicker" Sat Apr 4 19:05:58 2026 rev:4 rq:1344389 version:0.4.6 Changes: -------- --- /work/SRC/openSUSE:Factory/hyprpicker/hyprpicker.changes 2025-08-05 14:21:53.046736025 +0200 +++ /work/SRC/openSUSE:Factory/.hyprpicker.new.21863/hyprpicker.changes 2026-04-04 19:07:26.205172632 +0200 @@ -1,0 +2,19 @@ +Wed Apr 1 18:12:47 UTC 2026 - Bjørn Lie <[email protected]> + +- Update to version 0.4.6: + + Exit with a specific code when the user has cancelled picking a + color + + Update README.md + + Made preview format match output format + + nix: use gcc15 + + Notifications Support + + Fix flickering at top-left + + More flexible positioning and scaling + + Change css example in man page to use hsl + + feat: add custom format decoration + + Add null check for cursor shape device + + Feat: added keyboard movement +- Add 089dd8a448c12e1066486892de096590cddb4195.patch: core: Include + <mutex> to make pickier compilers happy. Fixes (boo#1260616). + +------------------------------------------------------------------- Old: ---- hyprpicker-0.4.5.obscpio New: ---- 089dd8a448c12e1066486892de096590cddb4195.patch hyprpicker-0.4.6.obscpio ----------(New B)---------- New: + Feat: added keyboard movement - Add 089dd8a448c12e1066486892de096590cddb4195.patch: core: Include <mutex> to make pickier compilers happy. Fixes (boo#1260616). ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ hyprpicker.spec ++++++ --- /var/tmp/diff_new_pack.2xndIn/_old 2026-04-04 19:07:26.769195757 +0200 +++ /var/tmp/diff_new_pack.2xndIn/_new 2026-04-04 19:07:26.773195921 +0200 @@ -1,7 +1,7 @@ # # spec file for package hyprpicker # -# Copyright (c) 2025 SUSE LLC and contributors +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,12 +17,13 @@ Name: hyprpicker -Version: 0.4.5 +Version: 0.4.6 Release: 0 Summary: A wlroots-compatible Wayland color picker License: BSD-3-Clause URL: https://github.com/hyprwm/hyprpicker Source: %{name}-%{version}.tar.gz +Patch: https://github.com/hyprwm/hyprpicker/commit/089dd8a448c12e1066486892de096590cddb4195.patch BuildRequires: cmake BuildRequires: gcc-c++ BuildRequires: ninja @@ -39,7 +40,7 @@ supports a few different output forms, e.g. RGB, CMYK, HSL, HSV. %prep -%autosetup +%autosetup -p1 %build %cmake ++++++ 089dd8a448c12e1066486892de096590cddb4195.patch ++++++ >From 089dd8a448c12e1066486892de096590cddb4195 Mon Sep 17 00:00:00 2001 From: Stephen Degler <[email protected]> Date: Tue, 10 Feb 2026 14:17:44 -0500 Subject: [PATCH] core: Include <mutex> to make pickier compilers happy. (#148) --- src/hyprpicker.cpp | 1 + src/hyprpicker.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 90f0228..d46959d 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -5,6 +5,7 @@ #include <cstddef> #include <cstdio> #include <format> +#include <mutex> #include <hyprutils/math/Vector2D.hpp> #include <wayland-client-protocol.h> #include <xkbcommon/xkbcommon-keysyms.h> diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index 77ab060..cad8f02 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -1,5 +1,6 @@ #pragma once +#include <mutex> #include "defines.hpp" #include "helpers/LayerSurface.hpp" #include "helpers/PoolBuffer.hpp" ++++++ hyprpicker-0.4.5.obscpio -> hyprpicker-0.4.6.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/README.md new/hyprpicker-0.4.6/README.md --- old/hyprpicker-0.4.5/README.md 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/README.md 2026-02-10 16:09:41.000000000 +0100 @@ -12,13 +12,13 @@ See `hyprpicker --help`. -# Building +# Installation ## Arch -`yay -S hyprpicker-git` +`sudo pacman -S hyprpicker` -## Manual +## Manual (Building) Install dependencies: - cmake @@ -46,3 +46,4 @@ # Caveats "Freezes" your displays when picking the color. + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/VERSION new/hyprpicker-0.4.6/VERSION --- old/hyprpicker-0.4.5/VERSION 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/VERSION 2026-02-10 16:09:41.000000000 +0100 @@ -1 +1 @@ -0.4.5 +0.4.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/doc/hyprpicker.1 new/hyprpicker-0.4.6/doc/hyprpicker.1 --- old/hyprpicker-0.4.5/doc/hyprpicker.1 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/doc/hyprpicker.1 2026-02-10 16:09:41.000000000 +0100 @@ -73,7 +73,7 @@ .Fn hsl function: .Pp -.Dl $ hyprpicker -f hsl | sed 's/^/rgb(/; s/$/)/; y/ /,/' +.Dl $ hyprpicker -f hsl | sed 's/^/hsl(/; s/$/)/; y/ /,/' .Sh SEE ALSO .Xr hyprctl 1 , .Xr hyprland 1 , diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/flake.lock new/hyprpicker-0.4.6/flake.lock --- old/hyprpicker-0.4.5/flake.lock 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/flake.lock 2026-02-10 16:09:41.000000000 +0100 @@ -10,11 +10,11 @@ ] }, "locked": { - "lastModified": 1737632363, - "narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=", + "lastModified": 1749135356, + "narHash": "sha256-Q8mAKMDsFbCEuq7zoSlcTuxgbIBVhfIYpX0RjE32PS0=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "006620eb29d54ea9086538891404c78563d1bae1", + "rev": "e36db00dfb3a3d3fdcc4069cb292ff60d2699ccb", "type": "github" }, "original": { @@ -33,11 +33,11 @@ ] }, "locked": { - "lastModified": 1735493474, - "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=", + "lastModified": 1749145760, + "narHash": "sha256-IHaGWpGrv7seFWdw/1A+wHtTsPlOGIKMrk1TUIYJEFI=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b", + "rev": "817918315ea016cc2d94004bfb3223b5fd9dfcc6", "type": "github" }, "original": { @@ -48,11 +48,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737469691, - "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=", + "lastModified": 1748929857, + "narHash": "sha256-lcZQ8RhsmhsK8u7LIFsJhsLh/pzR9yZ8yqpTzyGdj+Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab", + "rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4", "type": "github" }, "original": { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/flake.nix new/hyprpicker-0.4.6/flake.nix --- old/hyprpicker-0.4.5/flake.nix 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/flake.nix 2026-02-10 16:09:41.000000000 +0100 @@ -45,7 +45,7 @@ inputs.hyprwayland-scanner.overlays.default (final: prev: { hyprpicker = prev.callPackage ./nix/default.nix { - stdenv = prev.gcc14Stdenv; + stdenv = prev.gcc15Stdenv; version = version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty"); }; hyprpicker-debug = final.hyprpicker.override {debug = true;}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/clipboard/Clipboard.cpp new/hyprpicker-0.4.6/src/clipboard/Clipboard.cpp --- old/hyprpicker-0.4.5/src/clipboard/Clipboard.cpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/clipboard/Clipboard.cpp 2026-02-10 16:09:41.000000000 +0100 @@ -1,20 +1,12 @@ #include "Clipboard.hpp" #include "../includes.hpp" +#include <hyprutils/os/Process.hpp> +#include <string> +#include <vector> -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/clipboard/Clipboard.hpp new/hyprpicker-0.4.6/src/clipboard/Clipboard.hpp --- old/hyprpicker-0.4.5/src/clipboard/Clipboard.hpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/clipboard/Clipboard.hpp 2026-02-10 16:09:41.000000000 +0100 @@ -1,7 +1,7 @@ #pragma once -#define CLIPBOARDMESSAGESIZE 24 +#include <string> -namespace Clipboard { - void copy(const char* fmt, ...); -}; \ No newline at end of file +namespace NClipboard { + void copy(std::string data); +}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/defines.hpp new/hyprpicker-0.4.6/src/defines.hpp --- old/hyprpicker-0.4.5/src/defines.hpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/defines.hpp 2026-02-10 16:09:41.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/helpers/Color.cpp new/hyprpicker-0.4.6/src/helpers/Color.cpp --- old/hyprpicker-0.4.5/src/helpers/Color.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/hyprpicker-0.4.6/src/helpers/Color.cpp 2026-02-10 16:09:41.000000000 +0100 @@ -0,0 +1,80 @@ +#include "Color.hpp" +#include <algorithm> +#include "../hyprpicker.hpp" + +static float fmax3(float a, float b, float c) { + return (a > b && a > c) ? a : (b > c) ? b : c; +} + +static float fmin3(float a, float b, float c) { + return (a < b && a < c) ? a : (b < c) ? b : c; +} + +static bool floatEq(float a, float b) { + return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b && std::nextafter(a, std::numeric_limits<double>::max()) >= b; +} + +void CColor::getCMYK(float& c, float& m, float& y, float& k) const { + // http://www.codeproject.com/KB/applications/xcmyk.aspx + + float rf = 1 - (r / 255.0f), gf = 1 - (g / 255.0f), bf = 1 - (b / 255.0f); + k = fmin3(rf, gf, bf); + float K = (k == 1) ? 1 : 1 - k; + c = (rf - k) / K; + m = (gf - k) / K; + y = (bf - k) / K; + + c = std::round(c * 100); + m = std::round(m * 100); + y = std::round(y * 100); + k = std::round(k * 100); +} +void CColor::getHSV(float& h, float& s, float& v) const { + // https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB + + float rf = r / 255.0f, gf = g / 255.0f, bf = b / 255.0f; + float max = fmax3(rf, gf, bf), min = fmin3(rf, gf, bf); + float c = max - min; + + v = max; + if (c == 0) + h = 0; + else if (v == rf) + h = 60 * (0 + (gf - bf) / c); + else if (v == gf) + h = 60 * (2 + (bf - rf) / c); + else /* v == bf */ + h = 60 * (4 + (rf - gf) / c); + + v = max; + s = floatEq(v, 0.0f) ? 0 : c / v; + + h = std::round(h < 0 ? h + 360 : h); + v = std::round(v * 100); + s = std::round(s * 100); +} +void CColor::getHSL(float& h, float& s, float& l) const { + // https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB + + float rf = r / 255.0f, gf = g / 255.0f, bf = b / 255.0f, v; + float max = fmax3(rf, gf, bf), min = fmin3(rf, gf, bf); + float c = max - min; + + v = max; + if (c == 0) + h = 0; + else if (v == rf) + h = 60 * (0 + (gf - bf) / c); + else if (v == gf) + h = 60 * (2 + (bf - rf) / c); + else /* v == bf */ + h = 60 * (4 + (rf - gf) / c); + + v = max; + s = floatEq(v, 0.0f) ? 0 : c / v; + l = (max + min) / 2; + s = (floatEq(l, 0.0f) || floatEq(l, 1.0f)) ? 0 : (v - l) / std::min(l, 1 - l); + h = std::round(h < 0 ? h + 360 : h); + s = std::round(s * 100); + l = std::round(l * 100); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/helpers/Color.hpp new/hyprpicker-0.4.6/src/helpers/Color.hpp --- old/hyprpicker-0.4.5/src/helpers/Color.hpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/helpers/Color.hpp 2026-02-10 16:09:41.000000000 +0100 @@ -5,4 +5,7 @@ class CColor { public: uint8_t r = 0, g = 0, b = 0, a = 0; -}; \ No newline at end of file + void getCMYK(float& c, float& m, float& y, float& k) const; + void getHSV(float& h, float& s, float& v) const; + void getHSL(float& h, float& s, float& l) const; +}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/helpers/Monitor.cpp new/hyprpicker-0.4.6/src/helpers/Monitor.cpp --- old/hyprpicker-0.4.5/src/helpers/Monitor.cpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/helpers/Monitor.cpp 2026-02-10 16:09:41.000000000 +0100 @@ -118,4 +118,4 @@ Debug::log(CRIT, "Failed to get a Screencopy!"); g_pHyprpicker->finish(1); }); -} \ No newline at end of file +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/helpers/Monitor.hpp new/hyprpicker-0.4.6/src/helpers/Monitor.hpp --- old/hyprpicker-0.4.5/src/helpers/Monitor.hpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/helpers/Monitor.hpp 2026-02-10 16:09:41.000000000 +0100 @@ -14,11 +14,11 @@ 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; -}; \ No newline at end of file +}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/hyprpicker.cpp new/hyprpicker-0.4.6/src/hyprpicker.cpp --- old/hyprpicker-0.4.5/src/hyprpicker.cpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/hyprpicker.cpp 2026-02-10 16:09:41.000000000 +0100 @@ -1,7 +1,16 @@ #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> -void sigHandler(int sig) { +static void sigHandler(int sig) { g_pHyprpicker->m_vLayerSurfaces.clear(); exit(0); } @@ -9,7 +18,7 @@ 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); @@ -145,6 +154,116 @@ 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) { @@ -242,13 +361,13 @@ 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<ptrdiff_t>(y * (int)pBuffer->pixelSize.x * 4)) + (static_cast<ptrdiff_t>(x * 4))); std::swap(px->red, px->blue); } @@ -262,7 +381,7 @@ 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<ptrdiff_t>(y * (int)pBuffer->pixelSize.x * 4)) + (static_cast<ptrdiff_t>(x * 4))); // conv to 8 bit uint8_t R = (uint8_t)std::round((255.0 * (((*px) & 0b00000000000000000000001111111111) >> 0) / 1023.0)); @@ -292,19 +411,19 @@ 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<size_t>(y * pBuffer->stride)) + (static_cast<ptrdiff_t>(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<ptrdiff_t>(y * newBufferStride)) + (static_cast<ptrdiff_t>(x * 4))); *dstPx = {.blue = srcPx->red, .green = srcPx->green, .red = srcPx->blue, .alpha = 0xFF}; } } @@ -312,19 +431,19 @@ 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}; } } @@ -341,7 +460,8 @@ const auto PBUFFER = getBufferForLS(pSurface); if (!PBUFFER || !pSurface->screenBuffer) { - Debug::log(ERR, PBUFFER ? "renderSurface: pSurface->screenBuffer null" : "renderSurface: PBUFFER null"); + // Spammy log, doesn't matter. + // Debug::log(ERR, PBUFFER ? "renderSurface: pSurface->screenBuffer null" : "renderSurface: PBUFFER null"); return; } @@ -359,7 +479,7 @@ cairo_rectangle(PCAIRO, 0, 0, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y); cairo_fill(PCAIRO); - if (pSurface == m_pLastSurface && !forceInactive) { + if (pSurface == m_pLastSurface && !forceInactive && m_bCoordsInitialized) { const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize; const auto MOUSECOORDSABS = m_vLastCoords.floor() / pSurface->m_pMonitor->size; const auto CLICKPOS = MOUSECOORDSABS * PBUFFER->pixelSize; @@ -401,7 +521,7 @@ cairo_scale(PCAIRO, 1, 1); - cairo_arc(PCAIRO, CLICKPOS.x, CLICKPOS.y, 105 / SCALEBUFS.x, 0, 2 * M_PI); + cairo_arc(PCAIRO, CLICKPOS.x, CLICKPOS.y, m_iCircleRadius + 5 / SCALEBUFS.x, 0, 2 * M_PI); cairo_clip(PCAIRO); cairo_fill(PCAIRO); @@ -417,25 +537,58 @@ cairo_matrix_t matrix; cairo_matrix_init_identity(&matrix); cairo_matrix_translate(&matrix, CLICKPOSBUF.x + 0.5f, CLICKPOSBUF.y + 0.5f); - cairo_matrix_scale(&matrix, 0.1f, 0.1f); + cairo_matrix_scale(&matrix, 1.0 / m_fZoomScale, 1.0 / m_fZoomScale); cairo_matrix_translate(&matrix, (-CLICKPOSBUF.x / SCALEBUFS.x) - 0.5f, (-CLICKPOSBUF.y / SCALEBUFS.y) - 0.5f); cairo_pattern_set_matrix(PATTERN, &matrix); cairo_set_source(PCAIRO, PATTERN); - cairo_arc(PCAIRO, CLICKPOS.x, CLICKPOS.y, 100 / SCALEBUFS.x, 0, 2 * M_PI); + cairo_arc(PCAIRO, CLICKPOS.x, CLICKPOS.y, m_iCircleRadius / SCALEBUFS.x, 0, 2 * M_PI); cairo_clip(PCAIRO); cairo_paint(PCAIRO); - if (!m_bDisableHexPreview) { + if (!m_bDisablePreview) { const auto currentColor = getColorFromPixel(pSurface, CLICKPOS); - std::string hexBuffer; - if (m_bUseLowerCase) - hexBuffer = std::format("#{:02x}{:02x}{:02x}", currentColor.r, currentColor.g, currentColor.b); - else - hexBuffer = std::format("#{:02X}{:02X}{:02X}", currentColor.r, currentColor.g, currentColor.b); - - cairo_set_source_rgba(PCAIRO, 0.0, 0.0, 0.0, 0.5); + std::string previewBuffer; + switch (m_bSelectedOutputMode) { + case OUTPUT_HEX: { + std::string rHex, gHex, bHex; + if (m_bUseLowerCase) { + rHex = std::format("{:02x}", currentColor.r); + gHex = std::format("{:02x}", currentColor.g); + bHex = std::format("{:02x}", currentColor.b); + } else { + rHex = std::format("{:02X}", currentColor.r); + gHex = std::format("{:02X}", currentColor.g); + bHex = std::format("{:02X}", currentColor.b); + } + previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(rHex, gHex, bHex)); + break; + }; + case OUTPUT_RGB: { + previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(currentColor.r, currentColor.g, currentColor.b)); + break; + }; + case OUTPUT_HSL: { + float h, s, l; + currentColor.getHSL(h, s, l); + previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(h, s, l)); + break; + }; + case OUTPUT_HSV: { + float h, s, v; + currentColor.getHSV(h, s, v); + previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(h, s, v)); + break; + }; + case OUTPUT_CMYK: { + float c, m, y, k; + currentColor.getCMYK(c, m, y, k); + previewBuffer = std::vformat(m_sOutputFormat, std::make_format_args(c, m, y, k)); + break; + }; + }; + cairo_set_source_rgba(PCAIRO, 0.0, 0.0, 0.0, 0.75); - double x, y, width = 85, height = 28, radius = 6; + double x, y, width = 8 + (11 * previewBuffer.length()), height = 28, radius = 6; if (CLICKPOS.y > (PBUFFER->pixelSize.y - 50) && CLICKPOS.x > (PBUFFER->pixelSize.x - 100)) { x = CLICKPOS.x - 80; @@ -450,7 +603,7 @@ x = CLICKPOS.x; y = CLICKPOS.y + 20; } - + x -= 5.5 * previewBuffer.length(); cairo_move_to(PCAIRO, x + radius, y); cairo_arc(PCAIRO, x + width - radius, y + radius, radius, -M_PI_2, 0); cairo_arc(PCAIRO, x + width - radius, y + height - radius, radius, 0, M_PI_2); @@ -476,19 +629,19 @@ else cairo_move_to(PCAIRO, textX, CLICKPOS.y + 40); - cairo_show_text(PCAIRO, hexBuffer.c_str()); + cairo_show_text(PCAIRO, previewBuffer.c_str()); cairo_surface_flush(PBUFFER->surface); } cairo_restore(PCAIRO); cairo_pattern_destroy(PATTERN); } - } else if (!m_bRenderInactive) { + } else if (!m_bRenderInactive && m_bCoordsInitialized) { cairo_set_operator(PCAIRO, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0); cairo_rectangle(PCAIRO, 0, 0, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y); cairo_fill(PCAIRO); - } else { + } else if (m_bCoordsInitialized) { const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize; const auto PATTERNPRE = cairo_pattern_create_for_surface(pSurface->screenBuffer->surface); cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR); @@ -521,12 +674,13 @@ 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}; } @@ -567,12 +721,22 @@ 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) - finish(); + 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(); + finish(2); }); } @@ -581,7 +745,8 @@ auto x = wl_fixed_to_double(surface_x); auto y = wl_fixed_to_double(surface_y); - m_vLastCoords = {x, y}; + m_vLastCoords = {x, y}; + m_bCoordsInitialized = true; for (auto& ls : m_vLayerSurfaces) { if (ls->pSurface->resource() == surface) { @@ -590,7 +755,8 @@ } } - m_pCursorShapeDevice->sendSetShape(serial, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR); + if (m_pCursorShapeDevice) + m_pCursorShapeDevice->sendSetShape(serial, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR); markDirty(); }); @@ -613,134 +779,18 @@ markDirty(); }); - m_pPointer->setButton([this](CCWlPointer* r, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) { - auto fmax3 = [](float a, float b, float c) -> float { return (a > b && a > c) ? a : (b > c) ? b : c; }; - auto fmin3 = [](float a, float b, float c) -> float { return (a < b && a < c) ? a : (b < c) ? b : c; }; - - // 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; - - switch (m_bSelectedOutputMode) { - case OUTPUT_CMYK: { - // http://www.codeproject.com/KB/applications/xcmyk.aspx - - float r = 1 - (COL.r / 255.0f), g = 1 - (COL.g / 255.0f), b = 1 - (COL.b / 255.0f); - float k = fmin3(r, g, b), K = (k == 1) ? 1 : 1 - k; - float c = (r - k) / K, m = (g - k) / K, y = (b - k) / K; - - c = std::round(c * 100); - m = std::round(m * 100); - y = std::round(y * 100); - k = std::round(k * 100); - - 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); - 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()); - else - 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()); - finish(); - break; - } - case OUTPUT_RGB: { - 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); - finish(); - break; - } - case OUTPUT_HSL: - case OUTPUT_HSV: { - // https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB - - auto floatEq = [](float a, float b) -> bool { - return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b && std::nextafter(a, std::numeric_limits<double>::max()) >= b; - }; - - float h, s, l, v; - float r = COL.r / 255.0f, g = COL.g / 255.0f, b = COL.b / 255.0f; - float max = fmax3(r, g, b), min = fmin3(r, g, b); - float c = max - min; - - v = max; - if (c == 0) - h = 0; - else if (v == r) - h = 60 * (0 + (g - b) / c); - else if (v == g) - h = 60 * (2 + (b - r) / c); - else /* v == b */ - h = 60 * (4 + (r - g) / c); - - float l_or_v; - if (m_bSelectedOutputMode == OUTPUT_HSL) { - l = (max + min) / 2; - s = (floatEq(l, 0.0f) || floatEq(l, 1.0f)) ? 0 : (v - l) / std::min(l, 1 - l); - l_or_v = std::round(l * 100); - } else { - v = max; - s = floatEq(v, 0.0f) ? 0 : c / v; - l_or_v = std::round(v * 100); - } - - h = std::round(h < 0 ? h + 360 : h); - s = std::round(s * 100); + 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; - 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); + double delta = wl_fixed_to_double(value); - if (m_bAutoCopy) - Clipboard::copy("%g %g%% %g%%", h, s, l_or_v); - finish(); - break; - } - } + if (delta < 0) + m_fZoomScale = std::min(m_fZoomScale + 1.0, 100.0); + else + m_fZoomScale = std::max(m_fZoomScale - 1.0, 1.0); - finish(); + markDirty(); }); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/hyprpicker.hpp new/hyprpicker-0.4.6/src/hyprpicker.hpp --- old/hyprpicker-0.4.5/src/hyprpicker.hpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/hyprpicker.hpp 2026-02-10 16:09:41.000000000 +0100 @@ -4,14 +4,17 @@ #include "helpers/LayerSurface.hpp" #include "helpers/PoolBuffer.hpp" -enum eOutputMode { +// OUTPUT_COUNT is being used to count the number of output formats, it should always be last in the enum +enum eOutputMode : uint8_t { OUTPUT_CMYK = 0, OUTPUT_HEX, OUTPUT_RGB, OUTPUT_HSL, - OUTPUT_HSV + OUTPUT_HSV, }; +const std::array<uint8_t, 5> numOutputValues = {4, 3, 3, 3, 3}; + class CHyprpicker { public: void init(); @@ -37,17 +40,21 @@ xkb_state* m_pXKBState = nullptr; eOutputMode m_bSelectedOutputMode = OUTPUT_HEX; + std::string m_sOutputFormat = ""; bool m_bFancyOutput = true; - bool m_bAutoCopy = false; - bool m_bRenderInactive = false; - bool m_bNoZoom = false; - bool m_bNoFractional = false; - bool m_bDisableHexPreview = false; - bool m_bUseLowerCase = false; - - bool m_bRunning = true; + bool m_bAutoCopy = false; + bool m_bNotify = false; + bool m_bRenderInactive = false; + bool m_bNoZoom = false; + bool m_bNoFractional = false; + bool m_bDisablePreview = false; + bool m_bUseLowerCase = false; + + bool m_bRunning = true; + float m_fZoomScale = 10.0; + int m_iCircleRadius = 100; std::vector<std::unique_ptr<SMonitor>> m_vMonitors; std::vector<std::unique_ptr<CLayerSurface>> m_vLayerSurfaces; @@ -55,6 +62,7 @@ CLayerSurface* m_pLastSurface; Vector2D m_vLastCoords; + bool m_bCoordsInitialized = false; void renderSurface(CLayerSurface*, bool forceInactive = false); @@ -72,6 +80,7 @@ void markDirty(); void finish(int code = 0); + void outputColor(); CColor getColorFromPixel(CLayerSurface*, Vector2D); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/includes.hpp new/hyprpicker-0.4.6/src/includes.hpp --- old/hyprpicker-0.4.5/src/includes.hpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/includes.hpp 2026-02-10 16:09:41.000000000 +0100 @@ -35,7 +35,9 @@ #include <unordered_map> #include <hyprutils/memory/WeakPtr.hpp> +#include <hyprutils/os/Process.hpp> using namespace Hyprutils::Memory; +using namespace Hyprutils::OS; #define SP CSharedPointer #define WP CWeakPointer diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/main.cpp new/hyprpicker-0.4.6/src/main.cpp --- old/hyprpicker-0.4.5/src/main.cpp 2025-05-01 02:54:26.000000000 +0200 +++ new/hyprpicker-0.4.6/src/main.cpp 2026-02-10 16:09:41.000000000 +0100 @@ -1,22 +1,30 @@ +#include <cstdint> +#include <format> +#include <regex> #include <strings.h> #include <iostream> #include "hyprpicker.hpp" +#include "src/debug/Log.hpp" 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" + << " -o | --output-format=fmt | Specifies how the output color should be formatted e.g. rgb({0}, {1}, {2}) would output rgb(red, green, blue) if --format=rgb\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" << " -q | --quiet | Disable most logs (leaves errors)\n" << " -v | --verbose | Enable more logs\n" << " -t | --no-fractional | Disable fractional scaling support\n" - << " -d | --disable-hex-preview | Disable live preview of Hex code\n" + << " -d | --disable-preview | Disable live preview of color\n" << " -l | --lowercase-hex | Outputs the hexcode in lowercase\n" + << " -s | --scale=scale | Set the zoom scale (between 1 and 10)\n" + << " -u | --radius=radius | Set the circle radius (between 1 and 1000)\n" << " -V | --version | Print version info\n"; } @@ -27,19 +35,23 @@ int option_index = 0; static struct option long_options[] = {{"autocopy", no_argument, nullptr, 'a'}, {"format", required_argument, nullptr, 'f'}, + {"output-format", required_argument, nullptr, 'o'}, {"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'}, {"quiet", no_argument, nullptr, 'q'}, {"verbose", no_argument, nullptr, 'v'}, - {"disable-hex-preview", no_argument, nullptr, 'd'}, + {"disable-preview", no_argument, nullptr, 'd'}, {"lowercase-hex", no_argument, nullptr, 'l'}, {"version", no_argument, nullptr, 'V'}, + {"scale", required_argument, nullptr, 's'}, + {"radius", required_argument, nullptr, 'u'}, {nullptr, 0, nullptr, 0}}; - int c = getopt_long(argc, argv, ":f:hnarzqvtdlV", long_options, &option_index); + int c = getopt_long(argc, argv, ":f:o:hnbarzqvtdlVs:u:", long_options, &option_index); if (c == -1) break; @@ -60,21 +72,57 @@ exit(1); } break; + case 'o': g_pHyprpicker->m_sOutputFormat = optarg; 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; case 't': g_pHyprpicker->m_bNoFractional = true; break; case 'q': Debug::quiet = true; break; case 'v': Debug::verbose = true; break; - case 'd': g_pHyprpicker->m_bDisableHexPreview = true; break; + case 'd': g_pHyprpicker->m_bDisablePreview = true; break; case 'l': g_pHyprpicker->m_bUseLowerCase = true; break; case 'V': { std::cout << "hyprpicker v" << HYPRPICKER_VERSION << "\n"; exit(0); } + case 's': { + float value; + auto result = std::from_chars(optarg, optarg + strlen(optarg), value); + if (result.ec != std::errc() || result.ptr != optarg + strlen(optarg)) { + std::cerr << "Invalid scale value: " << optarg << "\n"; + exit(1); + } + + if (value < 1.0f || value > 10.0f) { + std::cerr << "Scale must be between 1 and 10!\n"; + exit(1); + } + + g_pHyprpicker->m_fZoomScale = value; + break; + } + + case 'u': { + int value; + auto result = std::from_chars(optarg, optarg + strlen(optarg), value); + + if (result.ec != std::errc() || result.ptr != optarg + strlen(optarg)) { + std::cerr << "Invalid radius value: " << optarg << "\n"; + exit(1); + } + + if (value < 1 || value > 1000) { + std::cerr << "Radius must be between 1 and 1000!\n"; + exit(1); + } + + g_pHyprpicker->m_iCircleRadius = value; + break; + } default: help(); exit(1); } } @@ -82,6 +130,23 @@ if (!isatty(fileno(stdout)) || getenv("NO_COLOR")) g_pHyprpicker->m_bFancyOutput = false; + if (g_pHyprpicker->m_sOutputFormat.empty()) { + switch (g_pHyprpicker->m_bSelectedOutputMode) { + case OUTPUT_CMYK: g_pHyprpicker->m_sOutputFormat = "{}% {}% {}% {}%"; break; + case OUTPUT_HEX: g_pHyprpicker->m_sOutputFormat = "#{}{}{}"; break; + case OUTPUT_RGB: g_pHyprpicker->m_sOutputFormat = "{} {} {}"; break; + case OUTPUT_HSL: g_pHyprpicker->m_sOutputFormat = "{} {}% {}%"; break; + case OUTPUT_HSV: g_pHyprpicker->m_sOutputFormat = "{} {}% {}%"; break; + } + } + try { + std::array<uint8_t, 4> dummy = {0, 0, 0, 0}; + (void)std::vformat(g_pHyprpicker->m_sOutputFormat, std::make_format_args(dummy[0], dummy[1], dummy[2], dummy[3])); + } catch (const std::format_error& e) { + Debug::log(NONE, "Invalid --output-format: %s", e.what()); + exit(1); + } + g_pHyprpicker->init(); return 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/notify/Notify.cpp new/hyprpicker-0.4.6/src/notify/Notify.cpp --- old/hyprpicker-0.4.5/src/notify/Notify.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/hyprpicker-0.4.6/src/notify/Notify.cpp 2026-02-10 16:09:41.000000000 +0100 @@ -0,0 +1,19 @@ +#include "Notify.hpp" + +#include "../includes.hpp" +#include <cstdint> +#include <cstdio> +#include <format> +#include <hyprutils/os/Process.hpp> +#include <iostream> +#include <string> + +#include <hyprutils/os/Process.hpp> + +void NNotify::send(std::string hexColor, std::string formattedColor) { + std::string notifyBody = std::format("<span>Selected color: <span color='{}'><b>{}</b></span></span>", hexColor, formattedColor); + + Hyprutils::OS::CProcess notify("notify-send", {"-t", "5000", "-i", "color-select-symbolic", "Color Picker", notifyBody}); + + notify.runAsync(); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hyprpicker-0.4.5/src/notify/Notify.hpp new/hyprpicker-0.4.6/src/notify/Notify.hpp --- old/hyprpicker-0.4.5/src/notify/Notify.hpp 1970-01-01 01:00:00.000000000 +0100 +++ new/hyprpicker-0.4.6/src/notify/Notify.hpp 2026-02-10 16:09:41.000000000 +0100 @@ -0,0 +1,8 @@ +#pragma once + +#include <cstdint> +#include <string> + +namespace NNotify { + void send(std::string hexColor, std::string formattedColor); +} ++++++ hyprpicker.obsinfo ++++++ --- /var/tmp/diff_new_pack.2xndIn/_old 2026-04-04 19:07:27.005205434 +0200 +++ /var/tmp/diff_new_pack.2xndIn/_new 2026-04-04 19:07:27.009205598 +0200 @@ -1,5 +1,5 @@ name: hyprpicker -version: 0.4.5 -mtime: 1746060866 -commit: 980ebd486b8a4c2ac1670286f38d163db1e38cd9 +version: 0.4.6 +mtime: 1770736181 +commit: 345eab2d704ee47a6c277cbfb2aeabaa620d9dbc
