Не отдам Gpick! Он хороший! Но крутить педали придётся…

от автора

Уже давно весьма огорчаюсь тем, что в моём любимом Gpick отвалилась пипетка с тех пор, как KDE со своей Плазмой прочно переехали на Wayland. Если раньше я ещё мирился с GTK-шностью Gpick (про KDE, плазму и вяленого — поручик, молчать!), то теперь совсем взгрустнулось…

Началось всё с того, что я напрочь забыл, какие у меня в «Местах» цвета какие. Я же человек правильный, нормальные человеческие названия для переменных ведь не путь джедая, верно? Посмотрев на своё

@mixin theme {    $color-01: rgba($col-36, $opacity-07);    $color-02: rgba($col-36, $opacity-11);    $color-03: rgba($col-36, $opacity-13);    $color-04: rgba($col-36, $opacity-12);…

(и ещё такого на пару сотен строк только в одном файле), я прослезился, ударил стену головой и решил исправляться к лучшему. Заодно перейти на адекватные CSS-переменные, а не этот SCSS-хардкор. Но вот без пипетки это грустновато…

Итак, нужна, прости Господи, пипетка. Ставить и терпеть ещё и штатный kcolorpicker, а уж тем более, kcolorchooser (при живом-то, ну, почти, Gpick) в своём уютном Artix я не намерен. Ладно про настройки я молчу, в которых у KDE-шных поделий обычно по две штуки — «Показывать иконку справа вместо слева» и «Рассказывать анекдоты раз в час вместо раза в полчаса». Но функционал… Непосредственного нету, а посредственного на полгига.

hyprpicker, который, как написано в пояснялке, does not suck, не просто wlroots-compatible. Проблема в том, что это я сейчас «wlroots-incompatible». Что остаётся? Правильно. Велосипедить.

Стал пытаться думать мозгом. Ударился было в bash-скрипты, но довольно быстро работать там с DBus, асинхронностью порталов и прочими мониторами стало очень больно.

Сунулся было набросать простенькую утилитку на C++/Qt (последний оборот звучит, правда? 😁) — стало ещё больнее. Ну, вы знаете. Для того, чтобы в дверь врезать новый замок, нам жизненно необходимо вокруг неё построить десятимиллионный мегаполис с инфраструктурой, аэропортом, полицией и трамвайной сетью. Не говоря уже о заведениях с преферансом и барышнями…

Короче, плюнул и наваял скрипт на Питоне (хоть я его и терпеть не могу). Получилось, имхо, просто прекрасно. При запуске даёт тебе пипетку, ждёт, пока жмакнешь ей где-нибудь на экране, и выдаёт на выход сразу пачку CSS-значений на любой вкус в таком виде:

HEX:  #7e80ea  HSL:  hsl(238 72% 70%)  RGBb: rgb(126 128 234)  RGBp: rgb(49.4% 50.2% 91.8%)

Тут тебе и RGB, хоть в HEX, хоть в числах байта, хоть в процентах, и HSL. А ежели запускать ещё и с ключиком -c или --copy, то заодно и копирует первое HEX-значение в буфер обмена. Можно повесить на хоткей хоть голым, хоть через какую-нибудь shell-трубу с опциональным парсером. Красота! 😁

В общем, делюсь с городом и миром. Может, кому-то пригодится и сэкономит нервы и время:

#!/usr/bin/env python3import sysimport colorsysimport subprocessimport argparsefrom gi.repository import GLib, Gioparser = argparse.ArgumentParser(    description="Wayland XDG-Portal Color Picker")parser.add_argument(    "-c", "--copy",     action="store_true",    help="Also, copy the HEX value to the clipboard")args = parser.parse_args()loop = GLib.MainLoop()channels = Nonebus = Gio.bus_get_sync(Gio.BusType.SESSION, None)def on_signal_received(    connection,    sender_name,    object_path,    interface_name,    signal_name,    parameters,    user_data):    global channels    try:        code, results = parameters.unpack()        if code == 0 and 'color' in results:            channels = results['color']    except Exception as e:        sys.stderr.write(f"Signal error: {e}\n")    finally:        loop.quit()def on_method_reply(connection, res):    try:        reply = connection.call_finish(res)        request_path = reply.unpack()[0]                bus.signal_subscribe(            "org.freedesktop.portal.Desktop",            "org.freedesktop.portal.Request",            "Response",            request_path,            None,            Gio.DBusSignalFlags.NONE,            on_signal_received,            None        )    except Exception as e:        sys.stderr.write(f"Method error: {e}\n")        loop.quit()bus.call(    "org.freedesktop.portal.Desktop",    "/org/freedesktop/portal/desktop",    "org.freedesktop.portal.Screenshot",    "PickColor",    GLib.Variant("(sa{sv})", ("", {})),    None,    Gio.DBusSignalFlags.NONE,    -1,    None,    on_method_reply)loop.run()if channels and len(channels) >= 3:    r_f, g_f, b_f = channels[0], channels[1], channels[2]        r_b, g_b, b_b = int(r_f * 255), int(g_f * 255), int(b_f * 255)    hex_color = f"#{r_b:02x}{g_b:02x}{b_b:02x}"    r_p, g_p, b_p = r_f * 100, g_f * 100, b_f * 100    h_f, l_f, s_f = colorsys.rgb_to_hls(r_f, g_f, b_f)    h, s, l = int(h_f * 360), int(s_f * 100), int(l_f * 100)        print(f"HEX:  {hex_color}")    print(f"HSL:  hsl({h} {s}% {l}%)")    print(f"RGBb: rgb({r_b} {g_b} {b_b})")    print(f"RGBp: rgb({r_p:.1f}% {g_p:.1f}% {b_p:.1f}%)")        if args.copy:        try:            subprocess.run(                ['wl-copy', hex_color],                check=True,                stdout=subprocess.DEVNULL,                stderr=subprocess.DEVNULL            )        except Exception:            try:                p = subprocess.Popen(                    ['xclip', '-selection', 'clipboard'],                    stdin=subprocess.PIPE,                    stdout=subprocess.DEVNULL,                    stderr=subprocess.DEVNULL                )                p.communicate(input=hex_color.encode())            except Exception:                pass    sys.exit(0)else:    sys.stderr.write("Cancelled by the user.\n")    sys.exit(1)

А если лениво отсюда копировать, закоммитил в своём GitHub-овском репозитории других полезняшек: ds-colorpicker.

Вот. Пользуйтесь, и больше велосипедов богу СПО! 😁

ссылка на оригинал статьи https://habr.com/ru/articles/1060500/