From c9238d39f64dd2618975c9d654301a4720659aed Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:58:43 +0100 Subject: [PATCH] core: move to hyprwayland-scanner (#88) * core: move to hyprwayland-scanner * Nix: add hw-s, bump flake * CMake: fix wl-client -> wl-scanner --------- Co-authored-by: Mihai Fufezan --- .gitignore | 6 + CMakeLists.txt | 84 +++---- flake.lock | 36 ++- flake.nix | 7 + nix/default.nix | 2 + src/events/Events.cpp | 450 ----------------------------------- src/events/Events.hpp | 78 ------ src/helpers/LayerSurface.cpp | 70 ++++-- src/helpers/LayerSurface.hpp | 32 +-- src/helpers/Monitor.cpp | 119 +++++++++ src/helpers/Monitor.hpp | 22 +- src/helpers/PoolBuffer.cpp | 42 ++++ src/helpers/PoolBuffer.hpp | 5 +- src/hyprpicker.cpp | 425 ++++++++++++++++++++++++--------- src/hyprpicker.hpp | 33 ++- src/includes.hpp | 28 +-- 16 files changed, 671 insertions(+), 768 deletions(-) delete mode 100644 src/events/Events.cpp delete mode 100644 src/events/Events.hpp create mode 100644 src/helpers/Monitor.cpp create mode 100644 src/helpers/PoolBuffer.cpp diff --git a/.gitignore b/.gitignore index 47c137e..918ed97 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,12 @@ result *.o *-protocol.c *-protocol.h + +protocols/*.cpp +protocols/*.hpp + +.cache/ + .ccls-cache gmon.out diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a78f06..0fdff9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,40 +38,6 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE) # -find_program(WaylandScanner NAMES wayland-scanner) -message(STATUS "Found WaylandScanner at ${WaylandScanner}") -execute_process( - COMMAND pkg-config --variable=pkgdatadir wayland-protocols - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE WAYLAND_PROTOCOLS_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) -message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") - -function(protocol protoPath protoName external) - if(external) - execute_process( - COMMAND ${WaylandScanner} client-header ${protoPath} - ${protoName}-protocol.h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - execute_process( - COMMAND ${WaylandScanner} private-code ${protoPath} - ${protoName}-protocol.c WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - # target_sources(hyprpicker PRIVATE ${protoName}-protocol.h) - target_sources(hyprpicker PRIVATE ${protoName}-protocol.h - ${protoName}-protocol.c) - else() - execute_process( - COMMAND ${WaylandScanner} client-header - ${WAYLAND_PROTOCOLS_DIR}/${protoPath} ${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - execute_process( - COMMAND ${WaylandScanner} private-code - ${WAYLAND_PROTOCOLS_DIR}/${protoPath} ${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(hyprpicker PRIVATE ${protoName}-protocol.h - ${protoName}-protocol.c) - endif() -endfunction() - include_directories(.) set(CMAKE_CXX_STANDARD 23) add_compile_options(-DWLR_USE_UNSTABLE) @@ -97,19 +63,53 @@ pkg_check_modules( pango pangocairo libjpeg - hyprutils>=0.2.0) + hyprutils>=0.2.0 + hyprwayland-scanner>=0.4.0) file(GLOB_RECURSE SRCFILES "src/*.cpp") add_executable(hyprpicker ${SRCFILES}) -protocol("protocols/wlr-layer-shell-unstable-v1.xml" - "wlr-layer-shell-unstable-v1" true) -protocol("protocols/wlr-screencopy-unstable-v1.xml" - "wlr-screencopy-unstable-v1" true) -protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) -protocol("staging/cursor-shape/cursor-shape-v1.xml" "wp-cursor-shape-v1" false) -protocol("unstable/tablet/tablet-unstable-v2.xml" "tablet-unstable-v2" false) +pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) +message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") +pkg_get_variable(WAYLAND_SCANNER_DIR wayland-scanner pkgdatadir) +message(STATUS "Found wayland-scanner at ${WAYLAND_SCANNER_DIR}") + +function(protocolnew protoPath protoName external) + if(external) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + else() + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + endif() + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp + ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp + COMMAND hyprwayland-scanner --client ${path}/${protoName}.xml + ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(hyprpicker PRIVATE protocols/${protoName}.cpp + protocols/${protoName}.hpp) +endfunction() +function(protocolWayland) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp + ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp + COMMAND hyprwayland-scanner --wayland-enums --client + ${WAYLAND_SCANNER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(hyprpicker PRIVATE protocols/wayland.cpp protocols/wayland.hpp) +endfunction() + +protocolwayland() + +protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolnew("protocols" "wlr-screencopy-unstable-v1" true) +protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) +protocolnew("staging/fractional-scale" "fractional-scale-v1" false) +protocolnew("stable/viewporter" "viewporter" false) +protocolnew("stable/xdg-shell" "xdg-shell" false) +protocolnew("staging/cursor-shape" "cursor-shape-v1" false) +protocolnew("stable/tablet" "tablet-v2" false) target_compile_definitions(hyprpicker PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") diff --git a/flake.lock b/flake.lock index 5abff22..9b970f7 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ ] }, "locked": { - "lastModified": 1721324102, - "narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=", + "lastModified": 1727300645, + "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "962582a090bc233c4de9d9897f46794280288989", + "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c", "type": "github" }, "original": { @@ -23,13 +23,36 @@ "type": "github" } }, + "hyprwayland-scanner": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1726874836, + "narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=", + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "rev": "500c81a9e1a76760371049a8d99e008ea77aa59e", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1721138476, - "narHash": "sha256-+W5eZOhhemLQxelojLxETfbFbc19NWawsXBlapYpqIA=", + "lastModified": 1727122398, + "narHash": "sha256-o8VBeCWHBxGd4kVMceIayf5GApqTavJbTa44Xcg5Rrk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ad0b5eed1b6031efaed382844806550c3dcb4206", + "rev": "30439d93eb8b19861ccbe3e581abf97bdc91b093", "type": "github" }, "original": { @@ -42,6 +65,7 @@ "root": { "inputs": { "hyprutils": "hyprutils", + "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", "systems": "systems" } diff --git a/flake.nix b/flake.nix index a246760..601a5b9 100644 --- a/flake.nix +++ b/flake.nix @@ -10,6 +10,12 @@ inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; }; + + hyprwayland-scanner = { + url = "github:hyprwm/hyprwayland-scanner"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + }; }; outputs = { @@ -36,6 +42,7 @@ default = self.overlays.hyprpicker; hyprpicker = lib.composeManyExtensions [ inputs.hyprutils.overlays.default + inputs.hyprwayland-scanner.overlays.default (final: prev: { hyprpicker = prev.callPackage ./nix/default.nix { stdenv = prev.gcc13Stdenv; diff --git a/nix/default.nix b/nix/default.nix index 0e64f6d..4ba945e 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -6,6 +6,7 @@ cairo, fribidi, hyprutils, + hyprwayland-scanner, libdatrie, libGL, libjpeg, @@ -37,6 +38,7 @@ stdenv.mkDerivation { nativeBuildInputs = [ cmake + hyprwayland-scanner pkg-config ]; diff --git a/src/events/Events.cpp b/src/events/Events.cpp deleted file mode 100644 index f8c333a..0000000 --- a/src/events/Events.cpp +++ /dev/null @@ -1,450 +0,0 @@ -#include "Events.hpp" - -#include "../hyprpicker.hpp" - -void Events::geometry(void* data, wl_output* output, int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, const char* make, const char* model, - int32_t transform) { - const auto PMONITOR = (SMonitor*)data; - - PMONITOR->transform = (wl_output_transform)transform; -} - -void Events::mode(void* data, wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { - // ignored -} - -void Events::done(void* data, wl_output* wl_output) { - const auto PMONITOR = (SMonitor*)data; - - PMONITOR->ready = true; -} - -void Events::scale(void* data, wl_output* wl_output, int32_t scale) { - const auto PMONITOR = (SMonitor*)data; - - PMONITOR->scale = scale; -} - -void Events::name(void* data, wl_output* wl_output, const char* name) { - const auto PMONITOR = (SMonitor*)data; - - if (name) - PMONITOR->name = name; -} - -void Events::description(void* data, wl_output* wl_output, const char* description) { - // i do not care -} - -void Events::ls_configure(void* data, zwlr_layer_surface_v1* surface, uint32_t serial, uint32_t width, uint32_t height) { - const auto PLAYERSURFACE = (CLayerSurface*)data; - - PLAYERSURFACE->m_pMonitor->size = Vector2D((int)width, (int)height); - - PLAYERSURFACE->ACKSerial = serial; - PLAYERSURFACE->wantsACK = true; - PLAYERSURFACE->working = true; - - g_pHyprpicker->recheckACK(); -} - -void Events::handleGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { - if (strcmp(interface, wl_compositor_interface.name) == 0) { - g_pHyprpicker->m_pCompositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, 4); - } else if (strcmp(interface, wl_shm_interface.name) == 0) { - g_pHyprpicker->m_pWLSHM = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1); - } else if (strcmp(interface, wl_output_interface.name) == 0) { - g_pHyprpicker->m_mtTickMutex.lock(); - - const auto PMONITOR = g_pHyprpicker->m_vMonitors.emplace_back(std::make_unique()).get(); - PMONITOR->wayland_name = name; - PMONITOR->name = ""; - PMONITOR->output = (wl_output*)wl_registry_bind(registry, name, &wl_output_interface, 4); - wl_output_add_listener(PMONITOR->output, &Events::outputListener, PMONITOR); - - g_pHyprpicker->m_mtTickMutex.unlock(); - } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { - g_pHyprpicker->m_pLayerShell = (zwlr_layer_shell_v1*)wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1); - } else if (strcmp(interface, wl_seat_interface.name) == 0) { - g_pHyprpicker->createSeat((wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1)); - } else if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) { - g_pHyprpicker->m_pSCMgr = (zwlr_screencopy_manager_v1*)wl_registry_bind(registry, name, &zwlr_screencopy_manager_v1_interface, 1); - } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { - g_pHyprpicker->m_pCursorShape = (wp_cursor_shape_manager_v1*)wl_registry_bind(registry, name, &wp_cursor_shape_manager_v1_interface, 1); - } -} - -void Events::handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name) { - // todo -} - -void Events::handleCapabilities(void* data, wl_seat* wl_seat, uint32_t capabilities) { - if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - const auto POINTER = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(POINTER, &pointerListener, wl_seat); - g_pHyprpicker->m_pCursorShapeDevice = (g_pHyprpicker->m_pCursorShape) ? wp_cursor_shape_manager_v1_get_pointer(g_pHyprpicker->m_pCursorShape, POINTER) : nullptr; - } else { - Debug::log(CRIT, "Hyprpicker cannot work without a pointer!"); - g_pHyprpicker->finish(1); - } - - if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - wl_keyboard_add_listener(wl_seat_get_keyboard(wl_seat), &keyboardListener, wl_seat); - } -} - -void Events::handlePointerEnter(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - auto x = wl_fixed_to_double(surface_x); - auto y = wl_fixed_to_double(surface_y); - - g_pHyprpicker->m_vLastCoords = {x, y}; - - g_pHyprpicker->markDirty(); - - for (auto& ls : g_pHyprpicker->m_vLayerSurfaces) { - if (ls->pSurface == surface) { - g_pHyprpicker->m_pLastSurface = ls.get(); - - if (!ls->pCursorImg) - break; - - if (g_pHyprpicker->m_pCursorShapeDevice) { - wp_cursor_shape_device_v1_set_shape(g_pHyprpicker->m_pCursorShapeDevice, serial, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR); - } else { - wl_surface_set_buffer_scale(ls->pCursorSurface, ls->m_pMonitor->scale); - wl_surface_attach(ls->pCursorSurface, wl_cursor_image_get_buffer(ls->pCursorImg), 0, 0); - wl_pointer_set_cursor(wl_pointer, serial, ls->pCursorSurface, ls->pCursorImg->hotspot_x / ls->m_pMonitor->scale, ls->pCursorImg->hotspot_y / ls->m_pMonitor->scale); - wl_surface_commit(ls->pCursorSurface); - } - } - } -} - -void Events::handlePointerLeave(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface) { - for (auto& ls : g_pHyprpicker->m_vLayerSurfaces) { - if (ls->pSurface == surface) { - g_pHyprpicker->renderSurface(ls.get(), true); - } - } -} - -void Events::handlePointerAxis(void* data, wl_pointer* wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { - // ignored -} - -void Events::handlePointerMotion(void* data, struct wl_pointer* wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - auto x = wl_fixed_to_double(surface_x); - auto y = wl_fixed_to_double(surface_y); - - g_pHyprpicker->m_vLastCoords = {x, y}; - - g_pHyprpicker->markDirty(); -} - -void Events::handlePointerButton(void* data, struct wl_pointer* wl_pointer, 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 SCALE = Vector2D{ - g_pHyprpicker->m_pLastSurface->screenBuffer.pixelSize.x / (g_pHyprpicker->m_pLastSurface->buffers[0].pixelSize.x / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale), - g_pHyprpicker->m_pLastSurface->screenBuffer.pixelSize.y / (g_pHyprpicker->m_pLastSurface->buffers[0].pixelSize.y / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale)}; - - const auto CLICKPOS = Vector2D{g_pHyprpicker->m_vLastCoords.floor().x * SCALE.x, g_pHyprpicker->m_vLastCoords.floor().y * SCALE.y}; - - const auto COL = g_pHyprpicker->getColorFromPixel(g_pHyprpicker->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 (g_pHyprpicker->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 (g_pHyprpicker->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 (g_pHyprpicker->m_bAutoCopy) - Clipboard::copy("%g%% %g%% %g%% %g%%", c, m, y, k); - g_pHyprpicker->finish(); - break; - } - case OUTPUT_HEX: { - auto toHex = [](int i) -> std::string { - const char* DS = "0123456789ABCDEF"; - - std::string result = ""; - - result += DS[i / 16]; - result += DS[i % 16]; - - return result; - }; - - if (g_pHyprpicker->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 (g_pHyprpicker->m_bAutoCopy) - Clipboard::copy("#%s%s%s", toHex(COL.r).c_str(), toHex(COL.g).c_str(), toHex(COL.b).c_str()); - g_pHyprpicker->finish(); - break; - } - case OUTPUT_RGB: { - if (g_pHyprpicker->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 (g_pHyprpicker->m_bAutoCopy) - Clipboard::copy("%i %i %i", COL.r, COL.g, COL.b); - g_pHyprpicker->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::lowest()) <= b && std::nextafter(a, std::numeric_limits::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 (g_pHyprpicker->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); - s = std::round(s * 100); - - if (g_pHyprpicker->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 (g_pHyprpicker->m_bAutoCopy) - Clipboard::copy("%g %g%% %g%%", h, s, l_or_v); - g_pHyprpicker->finish(); - break; - } - } - - g_pHyprpicker->finish(); -} - -void Events::handleKeyboardKeymap(void* data, wl_keyboard* wl_keyboard, uint format, int fd, uint size) { - if (!g_pHyprpicker->m_pXKBContext) - return; - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - Debug::log(ERR, "Could not recognise keymap format"); - return; - } - - const char* buf = (const char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (buf == MAP_FAILED) { - Debug::log(ERR, "Failed to mmap xkb keymap: %d", errno); - return; - } - - g_pHyprpicker->m_pXKBKeymap = xkb_keymap_new_from_buffer(g_pHyprpicker->m_pXKBContext, buf, size - 1, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - - munmap((void*)buf, size); - close(fd); - - if (!g_pHyprpicker->m_pXKBKeymap) { - Debug::log(ERR, "Failed to compile xkb keymap"); - return; - } - - g_pHyprpicker->m_pXKBState = xkb_state_new(g_pHyprpicker->m_pXKBKeymap); - if (!g_pHyprpicker->m_pXKBState) { - Debug::log(ERR, "Failed to create xkb state"); - return; - } -} - -void Events::handleKeyboardKey(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - if (state != WL_KEYBOARD_KEY_STATE_PRESSED) - return; - - if (g_pHyprpicker->m_pXKBState) { - if (xkb_state_key_get_one_sym(g_pHyprpicker->m_pXKBState, key + 8) == XKB_KEY_Escape) - g_pHyprpicker->finish(); - } else if (key == 1) // Assume keycode 1 is escape - g_pHyprpicker->finish(); -} - -void Events::handleKeyboardEnter(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface, wl_array* keys) {} - -void Events::handleKeyboardLeave(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface) {} - -void Events::handleKeyboardModifiers(void* data, wl_keyboard* wl_keyboard, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group) { - if (!g_pHyprpicker->m_pXKBState) - return; - - xkb_state_update_mask(g_pHyprpicker->m_pXKBState, mods_depressed, mods_latched, mods_locked, 0, 0, group); -} - -void Events::handleFrameDone(void* data, struct wl_callback* callback, uint32_t time) { - CLayerSurface* pLS = (CLayerSurface*)data; - - if (pLS->frame_callback) - wl_callback_destroy(pLS->frame_callback); - - pLS->frame_callback = nullptr; - - if (pLS->dirty || !pLS->rendered) - g_pHyprpicker->renderSurface(g_pHyprpicker->m_pLastSurface); -} - -void Events::handleBufferRelease(void* data, struct wl_buffer* wl_buffer) { - auto buf = (SPoolBuffer*)data; - buf->busy = false; -} - -void Events::handleSCBuffer(void* data, struct zwlr_screencopy_frame_v1* frame, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) { - const auto PLS = (CLayerSurface*)data; - - PLS->screenBufferFormat = format; - - if (!PLS->screenBuffer.buffer) - g_pHyprpicker->createBuffer(&PLS->screenBuffer, width, height, format, stride); - - zwlr_screencopy_frame_v1_copy(frame, PLS->screenBuffer.buffer); -} - -void Events::handleSCFlags(void* data, struct zwlr_screencopy_frame_v1* frame, uint32_t flags) { - const auto PLS = (CLayerSurface*)data; - - PLS->scflags = flags; - - g_pHyprpicker->recheckACK(); -} - -void Events::handleSCReady(void* lsdata, struct zwlr_screencopy_frame_v1* frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { - const auto PLS = (CLayerSurface*)lsdata; - - SPoolBuffer newBuf; - Vector2D transformedSize = PLS->screenBuffer.pixelSize; - - if (PLS->m_pMonitor->transform % 2 == 1) - std::swap(transformedSize.x, transformedSize.y); - - g_pHyprpicker->createBuffer(&newBuf, transformedSize.x, transformedSize.y, PLS->screenBufferFormat, transformedSize.x * 4); - - int bytesPerPixel = PLS->screenBuffer.stride / (int)PLS->screenBuffer.pixelSize.x; - void* data = PLS->screenBuffer.data; - if (bytesPerPixel == 4) - g_pHyprpicker->convertBuffer(&PLS->screenBuffer); - else if (bytesPerPixel == 3) { - Debug::log(WARN, "24 bit formats are unsupported, hyprpicker may or may not work as intended!"); - data = g_pHyprpicker->convert24To32Buffer(&PLS->screenBuffer); - PLS->screenBuffer.paddedData = data; - } else { - Debug::log(CRIT, "Unsupported stride/bytes per pixel %i", bytesPerPixel); - g_pHyprpicker->finish(1); - } - - cairo_surface_t* oldSurface = cairo_image_surface_create_for_data((unsigned char*)data, CAIRO_FORMAT_ARGB32, PLS->screenBuffer.pixelSize.x, PLS->screenBuffer.pixelSize.y, - PLS->screenBuffer.pixelSize.x * 4); - - cairo_surface_flush(oldSurface); - - newBuf.surface = cairo_image_surface_create_for_data((unsigned char*)newBuf.data, CAIRO_FORMAT_ARGB32, transformedSize.x, transformedSize.y, transformedSize.x * 4); - - const auto PCAIRO = cairo_create(newBuf.surface); - - auto cairoTransformMtx = [&](cairo_matrix_t* mtx) -> void { - const auto TR = PLS->m_pMonitor->transform % 4; - - if (TR == 0) - return; - - cairo_matrix_rotate(mtx, -M_PI_2 * (double)TR); - - if (TR == 1) - cairo_matrix_translate(mtx, -transformedSize.x, 0); - else if (TR == 2) - cairo_matrix_translate(mtx, -transformedSize.x, -transformedSize.y); - else if (TR == 3) - cairo_matrix_translate(mtx, 0, -transformedSize.y); - - // TODO: flipped - }; - - cairo_save(PCAIRO); - - cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0); - - cairo_rectangle(PCAIRO, 0, 0, 0xFFFF, 0xFFFF); - cairo_fill(PCAIRO); - - const auto PATTERNPRE = cairo_pattern_create_for_surface(oldSurface); - cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR); - cairo_matrix_t matrixPre; - cairo_matrix_init_identity(&matrixPre); - cairo_matrix_scale(&matrixPre, 1.0, 1.0); - cairoTransformMtx(&matrixPre); - cairo_pattern_set_matrix(PATTERNPRE, &matrixPre); - cairo_set_source(PCAIRO, PATTERNPRE); - cairo_paint(PCAIRO); - - cairo_surface_flush(newBuf.surface); - - cairo_pattern_destroy(PATTERNPRE); - - cairo_destroy(PCAIRO); - - cairo_surface_destroy(oldSurface); - - g_pHyprpicker->destroyBuffer(&PLS->screenBuffer); - - PLS->screenBuffer = newBuf; - - g_pHyprpicker->renderSurface(PLS); -} - -void Events::handleSCFailed(void* data, struct zwlr_screencopy_frame_v1* frame) { - Debug::log(CRIT, "Failed to get a Screencopy!"); - g_pHyprpicker->finish(1); -} diff --git a/src/events/Events.hpp b/src/events/Events.hpp deleted file mode 100644 index 8249111..0000000 --- a/src/events/Events.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include "../defines.hpp" - -namespace Events { - void geometry(void* data, wl_output* output, int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, const char* make, const char* model, - int32_t transform); - - void mode(void* data, wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh); - - void done(void* data, wl_output* wl_output); - - void scale(void* data, wl_output* wl_output, int32_t scale); - - void name(void* data, wl_output* wl_output, const char* name); - - void description(void* data, wl_output* wl_output, const char* description); - - void ls_configure(void* data, zwlr_layer_surface_v1* surface, uint32_t serial, uint32_t width, uint32_t height); - - void handleGlobal(void* data, wl_registry* registry, uint32_t name, const char* interface, uint32_t version); - - void handleGlobalRemove(void* data, wl_registry* registry, uint32_t name); - - void handleCapabilities(void* data, wl_seat* wl_seat, uint32_t capabilities); - - void handlePointerMotion(void* data, struct wl_pointer* wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y); - - void handlePointerButton(void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state); - - void handlePointerAxis(void* data, wl_pointer* wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value); - - void handlePointerEnter(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y); - - void handlePointerLeave(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface); - - void handleKeyboardKeymap(void* data, wl_keyboard* wl_keyboard, uint format, int fd, uint size); - - void handleKeyboardKey(void* data, struct wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state); - - void handleKeyboardEnter(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface, wl_array* keys); - - void handleKeyboardLeave(void* data, wl_keyboard* wl_keyboard, uint serial, wl_surface* surface); - - void handleKeyboardModifiers(void* data, wl_keyboard* wl_keyboard, uint serial, uint mods_depressed, uint mods_latched, uint mods_locked, uint group); - - void handleFrameDone(void* data, struct wl_callback* callback, uint32_t time); - - void handleBufferRelease(void* data, struct wl_buffer* wl_buffer); - - void handleSCBuffer(void* data, struct zwlr_screencopy_frame_v1* frame, uint32_t format, uint32_t width, uint32_t height, uint32_t stride); - - void handleSCFlags(void* data, struct zwlr_screencopy_frame_v1* frame, uint32_t flags); - - void handleSCReady(void* data, struct zwlr_screencopy_frame_v1* frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec); - - void handleSCFailed(void* data, struct zwlr_screencopy_frame_v1* frame); - - inline const wl_output_listener outputListener = {.geometry = geometry, .mode = mode, .done = done, .scale = scale, .name = name, .description = description}; - - inline const zwlr_layer_surface_v1_listener layersurfaceListener = {.configure = ls_configure}; - - inline const wl_registry_listener registryListener = {.global = handleGlobal, .global_remove = handleGlobalRemove}; - - inline const wl_seat_listener seatListener = {.capabilities = handleCapabilities}; - - inline const wl_pointer_listener pointerListener = { - .enter = handlePointerEnter, .leave = handlePointerLeave, .motion = handlePointerMotion, .button = handlePointerButton, .axis = handlePointerAxis}; - - inline const wl_keyboard_listener keyboardListener = { - .keymap = handleKeyboardKeymap, .enter = handleKeyboardEnter, .leave = handleKeyboardLeave, .key = handleKeyboardKey, .modifiers = handleKeyboardModifiers}; - - inline const wl_callback_listener frameListener = {.done = handleFrameDone}; - - inline const wl_buffer_listener bufferListener = {.release = handleBufferRelease}; - - inline const zwlr_screencopy_frame_v1_listener screencopyListener = {.buffer = handleSCBuffer, .flags = handleSCFlags, .ready = handleSCReady, .failed = handleSCFailed}; -}; diff --git a/src/helpers/LayerSurface.cpp b/src/helpers/LayerSurface.cpp index 50ff3cb..9b5c600 100644 --- a/src/helpers/LayerSurface.cpp +++ b/src/helpers/LayerSurface.cpp @@ -1,12 +1,11 @@ #include "LayerSurface.hpp" -#include "../events/Events.hpp" #include "../hyprpicker.hpp" CLayerSurface::CLayerSurface(SMonitor* pMonitor) { m_pMonitor = pMonitor; - pSurface = wl_compositor_create_surface(g_pHyprpicker->m_pCompositor); + pSurface = makeShared(g_pHyprpicker->m_pCompositor->sendCreateSurface()); if (!pSurface) { Debug::log(CRIT, "The compositor did not allow hyprpicker a surface!"); @@ -14,7 +13,8 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) { return; } - pLayerSurface = zwlr_layer_shell_v1_get_layer_surface(g_pHyprpicker->m_pLayerShell, pSurface, pMonitor->output, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "hyprpicker"); + pLayerSurface = makeShared( + g_pHyprpicker->m_pLayerShell->sendGetLayerSurface(pSurface->resource(), pMonitor->output->resource(), ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "hyprpicker")); if (!pLayerSurface) { Debug::log(CRIT, "The compositor did not allow hyprpicker a layersurface!"); @@ -22,25 +22,63 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) { return; } - zwlr_layer_surface_v1_set_size(pLayerSurface, 0, 0); - zwlr_layer_surface_v1_set_anchor( - pLayerSurface, ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); - zwlr_layer_surface_v1_set_exclusive_zone(pLayerSurface, -1); - zwlr_layer_surface_v1_set_keyboard_interactivity(pLayerSurface, true); - zwlr_layer_surface_v1_add_listener(pLayerSurface, &Events::layersurfaceListener, this); - wl_surface_commit(pSurface); + pLayerSurface->setConfigure([this](CCZwlrLayerSurfaceV1* r, uint32_t serial, uint32_t width, uint32_t height) { + m_pMonitor->size = {(double)width, (double)height}; + ACKSerial = serial; + wantsACK = true; + working = true; + + g_pHyprpicker->recheckACK(); + }); + + pLayerSurface->sendSetSize(0, 0); + pLayerSurface->sendSetAnchor((zwlrLayerSurfaceV1Anchor)(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)); + pLayerSurface->sendSetExclusiveZone(-1); + pLayerSurface->sendSetKeyboardInteractivity(1); + pSurface->sendCommit(); wl_display_flush(g_pHyprpicker->m_pWLDisplay); } CLayerSurface::~CLayerSurface() { - wl_surface_destroy(pSurface); - zwlr_layer_surface_v1_destroy(pLayerSurface); + pLayerSurface.reset(); + pSurface.reset(); + frameCallback.reset(); if (g_pHyprpicker->m_pWLDisplay) wl_display_flush(g_pHyprpicker->m_pWLDisplay); +} - g_pHyprpicker->destroyBuffer(&buffers[0]); - g_pHyprpicker->destroyBuffer(&buffers[1]); - g_pHyprpicker->destroyBuffer(&screenBuffer); -} \ No newline at end of file +// this has to be a separate function because frameCallback.reset() will destroy the listener func +static void onCallbackDone(CLayerSurface* surf, uint32_t when) { + surf->frameCallback.reset(); + + if (surf->dirty || !surf->rendered) + g_pHyprpicker->renderSurface(g_pHyprpicker->m_pLastSurface); +} + +void CLayerSurface::sendFrame() { + frameCallback = makeShared(pSurface->sendFrame()); + frameCallback->setDone([this](CCWlCallback* r, uint32_t when) { onCallbackDone(this, when); }); + + pSurface->sendAttach(lastBuffer == 0 ? buffers[0]->buffer.get() : buffers[1]->buffer.get(), 0, 0); + pSurface->sendSetBufferScale(m_pMonitor->scale); + pSurface->sendDamageBuffer(0, 0, 0xFFFF, 0xFFFF); + pSurface->sendCommit(); + + dirty = false; +} + +void CLayerSurface::markDirty() { + frameCallback = makeShared(pSurface->sendFrame()); + frameCallback->setDone([this](CCWlCallback* r, uint32_t when) { + frameCallback.reset(); + + if (dirty || !rendered) + g_pHyprpicker->renderSurface(g_pHyprpicker->m_pLastSurface); + }); + pSurface->sendCommit(); + + dirty = true; +} diff --git a/src/helpers/LayerSurface.hpp b/src/helpers/LayerSurface.hpp index 98f47ca..c6b7c2d 100644 --- a/src/helpers/LayerSurface.hpp +++ b/src/helpers/LayerSurface.hpp @@ -10,28 +10,28 @@ class CLayerSurface { CLayerSurface(SMonitor*); ~CLayerSurface(); - SMonitor* m_pMonitor = nullptr; + void sendFrame(); + void markDirty(); - zwlr_layer_surface_v1* pLayerSurface = nullptr; - wl_surface* pSurface = nullptr; - wl_surface* pCursorSurface = nullptr; + SMonitor* m_pMonitor = nullptr; - bool wantsACK = false; - uint32_t ACKSerial = 0; - bool working = false; + SP pLayerSurface = nullptr; + SP pSurface = nullptr; - int lastBuffer = 0; - SPoolBuffer buffers[2]; + bool wantsACK = false; + uint32_t ACKSerial = 0; + bool working = false; - SPoolBuffer screenBuffer; - uint32_t scflags = 0; - uint32_t screenBufferFormat = 0; + int lastBuffer = 0; + SP buffers[2]; - bool dirty = true; + SP screenBuffer; + uint32_t scflags = 0; + uint32_t screenBufferFormat = 0; - bool rendered = false; + bool dirty = true; - wl_callback* frame_callback = nullptr; + bool rendered = false; - wl_cursor_image* pCursorImg = nullptr; + SP frameCallback = nullptr; }; \ No newline at end of file diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp new file mode 100644 index 0000000..07a982b --- /dev/null +++ b/src/helpers/Monitor.cpp @@ -0,0 +1,119 @@ +#include "Monitor.hpp" +#include "LayerSurface.hpp" +#include "../hyprpicker.hpp" + +SMonitor::SMonitor(SP output_) : output(output_) { + output->setGeometry([this](CCWlOutput* r, int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, const char* make, const char* model, + int32_t transform_) { // + transform = (wl_output_transform)transform_; + }); + output->setDone([this](CCWlOutput* r) { // + ready = true; + }); + output->setScale([this](CCWlOutput* r, int32_t scale_) { // + scale = scale_; + }); + output->setName([this](CCWlOutput* r, const char* name_) { // + if (name_) + name = name_; + }); +} + +void SMonitor::initSCFrame() { + pSCFrame->setBuffer([this](CCZwlrScreencopyFrameV1* r, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) { + pLS->screenBufferFormat = format; + + if (!pLS->screenBuffer) + pLS->screenBuffer = makeShared(Vector2D{(double)width, (double)height}, format, stride); + + pSCFrame->sendCopy(pLS->screenBuffer->buffer->resource()); + }); + pSCFrame->setFlags([this](CCZwlrScreencopyFrameV1* r, uint32_t flags) { + pLS->scflags = flags; + + g_pHyprpicker->recheckACK(); + }); + pSCFrame->setReady([this](CCZwlrScreencopyFrameV1* r, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) { + Vector2D transformedSize = pLS->screenBuffer->pixelSize; + + if (pLS->m_pMonitor->transform % 2 == 1) + std::swap(transformedSize.x, transformedSize.y); + + SP newBuf = makeShared(transformedSize, pLS->screenBufferFormat, transformedSize.x * 4); + + int bytesPerPixel = pLS->screenBuffer->stride / (int)pLS->screenBuffer->pixelSize.x; + void* data = pLS->screenBuffer->data; + if (bytesPerPixel == 4) + g_pHyprpicker->convertBuffer(pLS->screenBuffer); + else if (bytesPerPixel == 3) { + Debug::log(WARN, "24 bit formats are unsupported, hyprpicker may or may not work as intended!"); + data = g_pHyprpicker->convert24To32Buffer(pLS->screenBuffer); + pLS->screenBuffer->paddedData = data; + } else { + Debug::log(CRIT, "Unsupported stride/bytes per pixel %i", bytesPerPixel); + g_pHyprpicker->finish(1); + } + + cairo_surface_t* oldSurface = cairo_image_surface_create_for_data((unsigned char*)data, CAIRO_FORMAT_ARGB32, pLS->screenBuffer->pixelSize.x, pLS->screenBuffer->pixelSize.y, + pLS->screenBuffer->pixelSize.x * 4); + + cairo_surface_flush(oldSurface); + + newBuf->surface = cairo_image_surface_create_for_data((unsigned char*)newBuf->data, CAIRO_FORMAT_ARGB32, transformedSize.x, transformedSize.y, transformedSize.x * 4); + + const auto PCAIRO = cairo_create(newBuf->surface); + + auto cairoTransformMtx = [&](cairo_matrix_t* mtx) -> void { + const auto TR = pLS->m_pMonitor->transform % 4; + + if (TR == 0) + return; + + cairo_matrix_rotate(mtx, -M_PI_2 * (double)TR); + + if (TR == 1) + cairo_matrix_translate(mtx, -transformedSize.x, 0); + else if (TR == 2) + cairo_matrix_translate(mtx, -transformedSize.x, -transformedSize.y); + else if (TR == 3) + cairo_matrix_translate(mtx, 0, -transformedSize.y); + + // TODO: flipped + }; + + cairo_save(PCAIRO); + + cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0); + + cairo_rectangle(PCAIRO, 0, 0, 0xFFFF, 0xFFFF); + cairo_fill(PCAIRO); + + const auto PATTERNPRE = cairo_pattern_create_for_surface(oldSurface); + cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR); + cairo_matrix_t matrixPre; + cairo_matrix_init_identity(&matrixPre); + cairo_matrix_scale(&matrixPre, 1.0, 1.0); + cairoTransformMtx(&matrixPre); + cairo_pattern_set_matrix(PATTERNPRE, &matrixPre); + cairo_set_source(PCAIRO, PATTERNPRE); + cairo_paint(PCAIRO); + + cairo_surface_flush(newBuf->surface); + + cairo_pattern_destroy(PATTERNPRE); + + cairo_destroy(PCAIRO); + + cairo_surface_destroy(oldSurface); + + pLS->screenBuffer = newBuf; + + g_pHyprpicker->renderSurface(pLS); + + pSCFrame.reset(); + }); + pSCFrame->setFailed([this](CCZwlrScreencopyFrameV1* r) { + Debug::log(CRIT, "Failed to get a Screencopy!"); + g_pHyprpicker->finish(1); + }); +} \ No newline at end of file diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index cbd9232..999359b 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -4,15 +4,21 @@ #include using namespace Hyprutils::Math; +class CLayerSurface; + struct SMonitor { - std::string name = ""; - wl_output* output = nullptr; - uint32_t wayland_name = 0; - Vector2D size; - int scale; - wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + SMonitor(SP output_); + void initSCFrame(); - bool ready = false; + std::string name = ""; + SP output = nullptr; + uint32_t wayland_name = 0; + Vector2D size; + int scale; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; - zwlr_screencopy_frame_v1* pSCFrame = nullptr; + bool ready = false; + + CLayerSurface* pLS = nullptr; + SP pSCFrame = nullptr; }; \ No newline at end of file diff --git a/src/helpers/PoolBuffer.cpp b/src/helpers/PoolBuffer.cpp new file mode 100644 index 0000000..9d40f7d --- /dev/null +++ b/src/helpers/PoolBuffer.cpp @@ -0,0 +1,42 @@ +#include "PoolBuffer.hpp" +#include "../hyprpicker.hpp" + +SPoolBuffer::SPoolBuffer(const Vector2D& pixelSize_, uint32_t format_, uint32_t stride_) : stride(stride_), pixelSize(pixelSize_), format(format_) { + const size_t SIZE = stride * pixelSize.y; + + const auto FD = g_pHyprpicker->createPoolFile(SIZE, name); + + if (FD == -1) { + Debug::log(CRIT, "Unable to create pool file!"); + g_pHyprpicker->finish(1); + } + + const auto DATA = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, FD, 0); + + size = SIZE; + data = DATA; + + auto POOL = makeShared(g_pHyprpicker->m_pSHM->sendCreatePool(FD, SIZE)); + buffer = makeShared(POOL->sendCreateBuffer(0, pixelSize.x, pixelSize.y, stride, format)); + + buffer->setRelease([this](CCWlBuffer* r) { busy = false; }); + + POOL.reset(); + + close(FD); +} + +SPoolBuffer::~SPoolBuffer() { + buffer.reset(); + cairo_destroy(cairo); + cairo_surface_destroy(surface); + munmap(data, size); + + cairo = nullptr; + surface = nullptr; + + unlink(name.c_str()); + + if (paddedData) + free(paddedData); +} \ No newline at end of file diff --git a/src/helpers/PoolBuffer.hpp b/src/helpers/PoolBuffer.hpp index 7a397ea..2d9c6ad 100644 --- a/src/helpers/PoolBuffer.hpp +++ b/src/helpers/PoolBuffer.hpp @@ -3,7 +3,10 @@ #include "../defines.hpp" struct SPoolBuffer { - wl_buffer* buffer = nullptr; + SPoolBuffer(const Vector2D& size, uint32_t format, uint32_t stride); + ~SPoolBuffer(); + + SP buffer = nullptr; cairo_surface_t* surface = nullptr; cairo_t* cairo = nullptr; void* data = nullptr; diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index e60e3c2..8543cd3 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -1,6 +1,5 @@ #include "hyprpicker.hpp" #include -#include "events/Events.hpp" void sigHandler(int sig) { g_pHyprpicker->m_vLayerSurfaces.clear(); @@ -22,22 +21,76 @@ void CHyprpicker::init() { signal(SIGTERM, sigHandler); - m_pWLRegistry = wl_display_get_registry(m_pWLDisplay); + m_pRegistry = makeShared((wl_proxy*)wl_display_get_registry(m_pWLDisplay)); + m_pRegistry->setGlobal([this](CCWlRegistry* r, uint32_t name, const char* interface, uint32_t version) { + if (strcmp(interface, wl_compositor_interface.name) == 0) { + m_pCompositor = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wl_compositor_interface, 4)); + } else if (strcmp(interface, wl_shm_interface.name) == 0) { + m_pSHM = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wl_shm_interface, 1)); + } else if (strcmp(interface, wl_output_interface.name) == 0) { + m_mtTickMutex.lock(); - wl_registry_add_listener(m_pWLRegistry, &Events::registryListener, nullptr); + const auto PMONITOR = g_pHyprpicker->m_vMonitors + .emplace_back(std::make_unique( + makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wl_output_interface, 4)))) + .get(); + PMONITOR->wayland_name = name; + + m_mtTickMutex.unlock(); + } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { + m_pLayerShell = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &zwlr_layer_shell_v1_interface, 1)); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + m_pSeat = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wl_seat_interface, 1)); + + m_pSeat->setCapabilities([this](CCWlSeat* seat, uint32_t caps) { + if (caps & WL_SEAT_CAPABILITY_POINTER) { + if (!m_pPointer) { + m_pPointer = makeShared(m_pSeat->sendGetPointer()); + initMouse(); + if (m_pCursorShapeMgr) + m_pCursorShapeDevice = makeShared(m_pCursorShapeMgr->sendGetPointer(m_pPointer->resource())); + } + } else { + Debug::log(CRIT, "Hyprpicker cannot work without a pointer!"); + g_pHyprpicker->finish(1); + } + + if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { + if (!m_pKeyboard) { + m_pKeyboard = makeShared(m_pSeat->sendGetKeyboard()); + initKeyboard(); + } + } else + m_pKeyboard.reset(); + }); + + } else if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) { + m_pScreencopyMgr = + makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &zwlr_screencopy_manager_v1_interface, 1)); + } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { + m_pCursorShapeMgr = + makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_cursor_shape_manager_v1_interface, 1)); + } + }); wl_display_roundtrip(m_pWLDisplay); + if (!m_pCursorShapeMgr) + Debug::log(ERR, "cursor_shape_v1 not supported, cursor won't be affected"); + + if (!m_pScreencopyMgr) { + Debug::log(CRIT, "zwlr_screencopy_v1 not supported, can't proceed"); + exit(1); + } + for (auto& m : m_vMonitors) { m_vLayerSurfaces.emplace_back(std::make_unique(m.get())); m_pLastSurface = m_vLayerSurfaces.back().get(); - m->pSCFrame = zwlr_screencopy_manager_v1_capture_output(m_pSCMgr, false, m->output); - - zwlr_screencopy_frame_v1_add_listener(m->pSCFrame, &Events::screencopyListener, m_pLastSurface); - - m_pLastSurface->pCursorSurface = wl_compositor_create_surface(m_pCompositor); + m->pSCFrame = makeShared(m_pScreencopyMgr->sendCaptureOutput(false, m->output->resource())); + m->pLS = m_vLayerSurfaces.back().get(); + m->initSCFrame(); } wl_display_roundtrip(m_pWLDisplay); @@ -56,6 +109,19 @@ void CHyprpicker::finish(int code) { m_vLayerSurfaces.clear(); if (m_pWLDisplay) { + m_vLayerSurfaces.clear(); + m_vMonitors.clear(); + m_pCompositor.reset(); + m_pRegistry.reset(); + m_pSHM.reset(); + m_pLayerShell.reset(); + m_pScreencopyMgr.reset(); + m_pCursorShapeMgr.reset(); + m_pCursorShapeDevice.reset(); + m_pSeat.reset(); + m_pKeyboard.reset(); + m_pPointer.reset(); + wl_display_disconnect(m_pWLDisplay); m_pWLDisplay = nullptr; } @@ -65,29 +131,13 @@ void CHyprpicker::finish(int code) { void CHyprpicker::recheckACK() { for (auto& ls : m_vLayerSurfaces) { - if (ls->wantsACK && ls->screenBuffer.buffer) { + if (ls->wantsACK) { ls->wantsACK = false; - zwlr_layer_surface_v1_ack_configure(ls->pLayerSurface, ls->ACKSerial); + ls->pLayerSurface->sendAckConfigure(ls->ACKSerial); - if (!ls->buffers[0].buffer) { - createBuffer(&ls->buffers[0], ls->m_pMonitor->size.x * ls->m_pMonitor->scale, ls->m_pMonitor->size.y * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, - ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4); - createBuffer(&ls->buffers[1], ls->m_pMonitor->size.x * ls->m_pMonitor->scale, ls->m_pMonitor->size.y * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, - ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4); - - int XCURSOR_SIZE = 24; - if (getenv("XCURSOR_SIZE")) { - XCURSOR_SIZE = std::stoi(getenv("XCURSOR_SIZE")); - } - - const auto THEME = wl_cursor_theme_load(getenv("XCURSOR_THEME"), XCURSOR_SIZE * ls->m_pMonitor->scale, m_pWLSHM); - auto cursor = wl_cursor_theme_get_cursor(THEME, "crosshair"); - - if (!cursor) - cursor = wl_cursor_theme_get_cursor(THEME, "left_ptr"); - - if (cursor) - ls->pCursorImg = cursor->images[0]; + if (!ls->buffers[0] || ls->buffers[0]->pixelSize != ls->m_pMonitor->size * ls->m_pMonitor->scale) { + ls->buffers[0] = makeShared(ls->m_pMonitor->size * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4); + ls->buffers[1] = makeShared(ls->m_pMonitor->size * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4); } } } @@ -97,30 +147,23 @@ void CHyprpicker::recheckACK() { void CHyprpicker::markDirty() { for (auto& ls : m_vLayerSurfaces) { - if (ls->frame_callback) + if (ls->frameCallback) continue; - ls->frame_callback = wl_surface_frame(ls->pSurface); - wl_callback_add_listener(ls->frame_callback, &Events::frameListener, ls.get()); - wl_surface_commit(ls->pSurface); - - ls->dirty = true; + ls->markDirty(); } } -SPoolBuffer* CHyprpicker::getBufferForLS(CLayerSurface* pLS) { - SPoolBuffer* returns = nullptr; +SP CHyprpicker::getBufferForLS(CLayerSurface* pLS) { + SP returns = nullptr; for (auto i = 0; i < 2; ++i) { - if (pLS->buffers[i].busy) + if (!pLS->buffers[i] || pLS->buffers[i]->busy) continue; - returns = &pLS->buffers[i]; + returns = pLS->buffers[i]; } - if (!returns) - return nullptr; - return returns; } @@ -167,57 +210,7 @@ int CHyprpicker::createPoolFile(size_t size, std::string& name) { return FD; } -void CHyprpicker::createBuffer(SPoolBuffer* pBuffer, int32_t w, int32_t h, uint32_t format, uint32_t stride) { - const size_t SIZE = stride * h; - - std::string name; - const auto FD = createPoolFile(SIZE, name); - - if (FD == -1) { - Debug::log(CRIT, "Unable to create pool file!"); - g_pHyprpicker->finish(1); - } - - const auto DATA = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, FD, 0); - const auto POOL = wl_shm_create_pool(g_pHyprpicker->m_pWLSHM, FD, SIZE); - pBuffer->buffer = wl_shm_pool_create_buffer(POOL, 0, w, h, stride, format); - - wl_buffer_add_listener(pBuffer->buffer, &Events::bufferListener, pBuffer); - - wl_shm_pool_destroy(POOL); - - close(FD); - - pBuffer->format = format; - pBuffer->size = SIZE; - pBuffer->data = DATA; - pBuffer->pixelSize = Vector2D(w, h); - pBuffer->name = name; - pBuffer->stride = stride; -} - -void CHyprpicker::destroyBuffer(SPoolBuffer* pBuffer) { - wl_buffer_destroy(pBuffer->buffer); - cairo_destroy(pBuffer->cairo); - cairo_surface_destroy(pBuffer->surface); - munmap(pBuffer->data, pBuffer->size); - - pBuffer->buffer = nullptr; - pBuffer->cairo = nullptr; - pBuffer->surface = nullptr; - - unlink(pBuffer->name.c_str()); - - if (pBuffer->paddedData) { - free(pBuffer->paddedData); - } -} - -void CHyprpicker::createSeat(wl_seat* pSeat) { - wl_seat_add_listener(pSeat, &Events::seatListener, pSeat); -} - -void CHyprpicker::convertBuffer(SPoolBuffer* pBuffer) { +void CHyprpicker::convertBuffer(SP pBuffer) { switch (pBuffer->format) { case WL_SHM_FORMAT_ARGB8888: case WL_SHM_FORMAT_XRGB8888: break; @@ -268,7 +261,7 @@ void CHyprpicker::convertBuffer(SPoolBuffer* pBuffer) { } // Mallocs a new buffer, which needs to be free'd! -void* CHyprpicker::convert24To32Buffer(SPoolBuffer* pBuffer) { +void* CHyprpicker::convert24To32Buffer(SP pBuffer) { uint8_t* newBuffer = (uint8_t*)malloc((size_t)pBuffer->pixelSize.x * pBuffer->pixelSize.y * 4); int newBufferStride = pBuffer->pixelSize.x * 4; uint8_t* oldBuffer = (uint8_t*)pBuffer->data; @@ -325,8 +318,8 @@ void* CHyprpicker::convert24To32Buffer(SPoolBuffer* pBuffer) { void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { const auto PBUFFER = getBufferForLS(pSurface); - if (!PBUFFER || !pSurface->screenBuffer.buffer) { - Debug::log(ERR, PBUFFER ? "renderSurface: pSurface->screenBuffer.buffer null" : "renderSurface: PBUFFER null"); + if (!PBUFFER || !pSurface->screenBuffer) { + // Debug::log(ERR, PBUFFER ? "renderSurface: pSurface->screenBuffer null" : "renderSurface: PBUFFER null"); return; } @@ -345,13 +338,13 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_fill(PCAIRO); if (pSurface == g_pHyprpicker->m_pLastSurface && !forceInactive) { - const auto SCALEBUFS = Vector2D{pSurface->screenBuffer.pixelSize.x / PBUFFER->pixelSize.x, pSurface->screenBuffer.pixelSize.y / PBUFFER->pixelSize.y}; + const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize; const auto SCALECURSOR = Vector2D{ - g_pHyprpicker->m_pLastSurface->screenBuffer.pixelSize.x / (g_pHyprpicker->m_pLastSurface->buffers[0].pixelSize.x / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale), - g_pHyprpicker->m_pLastSurface->screenBuffer.pixelSize.y / (g_pHyprpicker->m_pLastSurface->buffers[0].pixelSize.y / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale)}; + g_pHyprpicker->m_pLastSurface->screenBuffer->pixelSize.x / (g_pHyprpicker->m_pLastSurface->buffers[0]->pixelSize.x / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale), + g_pHyprpicker->m_pLastSurface->screenBuffer->pixelSize.y / (g_pHyprpicker->m_pLastSurface->buffers[0]->pixelSize.y / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale)}; const auto CLICKPOS = Vector2D{g_pHyprpicker->m_vLastCoords.floor().x * SCALECURSOR.x, g_pHyprpicker->m_vLastCoords.floor().y * SCALECURSOR.y}; - const auto PATTERNPRE = cairo_pattern_create_for_surface(pSurface->screenBuffer.surface); + const auto PATTERNPRE = cairo_pattern_create_for_surface(pSurface->screenBuffer->surface); cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR); cairo_matrix_t matrixPre; cairo_matrix_init_identity(&matrixPre); @@ -394,7 +387,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_restore(PCAIRO); cairo_save(PCAIRO); - const auto PATTERN = cairo_pattern_create_for_surface(pSurface->screenBuffer.surface); + const auto PATTERN = cairo_pattern_create_for_surface(pSurface->screenBuffer->surface); cairo_pattern_set_filter(PATTERN, CAIRO_FILTER_NEAREST); cairo_matrix_t matrix; cairo_matrix_init_identity(&matrix); @@ -419,8 +412,8 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_rectangle(PCAIRO, 0, 0, pSurface->m_pMonitor->size.x * pSurface->m_pMonitor->scale, pSurface->m_pMonitor->size.y * pSurface->m_pMonitor->scale); cairo_fill(PCAIRO); } else { - const auto SCALEBUFS = Vector2D{pSurface->screenBuffer.pixelSize.x / PBUFFER->pixelSize.x, pSurface->screenBuffer.pixelSize.y / PBUFFER->pixelSize.y}; - const auto PATTERNPRE = cairo_pattern_create_for_surface(pSurface->screenBuffer.surface); + 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); cairo_matrix_t matrixPre; cairo_matrix_init_identity(&matrixPre); @@ -434,7 +427,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_pattern_destroy(PATTERNPRE); } - sendFrame(pSurface); + pSurface->sendFrame(); cairo_destroy(PCAIRO); cairo_surface_destroy(PBUFFER->surface); @@ -445,26 +438,222 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { pSurface->rendered = true; } -void CHyprpicker::sendFrame(CLayerSurface* pSurface) { - pSurface->frame_callback = wl_surface_frame(pSurface->pSurface); - wl_callback_add_listener(pSurface->frame_callback, &Events::frameListener, pSurface); - - wl_surface_attach(pSurface->pSurface, pSurface->lastBuffer == 0 ? pSurface->buffers[0].buffer : pSurface->buffers[1].buffer, 0, 0); - wl_surface_set_buffer_scale(pSurface->pSurface, pSurface->m_pMonitor->scale); - wl_surface_damage_buffer(pSurface->pSurface, 0, 0, 0xFFFF, 0xFFFF); - wl_surface_commit(pSurface->pSurface); - - pSurface->dirty = false; -} - CColor CHyprpicker::getColorFromPixel(CLayerSurface* pLS, Vector2D pix) { - void* dataSrc = pLS->screenBuffer.paddedData ? pLS->screenBuffer.paddedData : pLS->screenBuffer.data; + void* dataSrc = pLS->screenBuffer->paddedData ? pLS->screenBuffer->paddedData : pLS->screenBuffer->data; struct pixel { unsigned char blue; unsigned char green; unsigned char red; unsigned char alpha; - }* px = (struct pixel*)((char*)dataSrc + (int)pix.y * (int)pLS->screenBuffer.pixelSize.x * 4 + (int)pix.x * 4); + }* px = (struct pixel*)((char*)dataSrc + (int)pix.y * (int)pLS->screenBuffer->pixelSize.x * 4 + (int)pix.x * 4); return CColor{(uint8_t)px->red, (uint8_t)px->green, (uint8_t)px->blue, (uint8_t)px->alpha}; } + +void CHyprpicker::initKeyboard() { + m_pKeyboard->setKeymap([this](CCWlKeyboard* r, wl_keyboard_keymap_format format, int32_t fd, uint32_t size) { + if (!m_pXKBContext) + return; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + Debug::log(ERR, "Could not recognise keymap format"); + return; + } + + const char* buf = (const char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (buf == MAP_FAILED) { + Debug::log(ERR, "Failed to mmap xkb keymap: %d", errno); + return; + } + + m_pXKBKeymap = xkb_keymap_new_from_buffer(m_pXKBContext, buf, size - 1, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + + munmap((void*)buf, size); + close(fd); + + if (!m_pXKBKeymap) { + Debug::log(ERR, "Failed to compile xkb keymap"); + return; + } + + m_pXKBState = xkb_state_new(m_pXKBKeymap); + if (!m_pXKBState) { + Debug::log(ERR, "Failed to create xkb state"); + return; + } + }); + + 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(); + } else if (key == 1) // Assume keycode 1 is escape + finish(); + }); +} + +void CHyprpicker::initMouse() { + m_pPointer->setEnter([this](CCWlPointer* r, uint32_t serial, wl_resource* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + auto x = wl_fixed_to_double(surface_x); + auto y = wl_fixed_to_double(surface_y); + + m_vLastCoords = {x, y}; + + markDirty(); + + for (auto& ls : m_vLayerSurfaces) { + if (ls->pSurface->resource() == surface) { + m_pLastSurface = ls.get(); + break; + } + } + + m_pCursorShapeDevice->sendSetShape(serial, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR); + }); + m_pPointer->setLeave([this](CCWlPointer* r, uint32_t timeMs, wl_resource* surf) { + for (auto& ls : m_vLayerSurfaces) { + if (ls->pSurface->resource() == surf) { + renderSurface(ls.get(), true); + } + } + }); + m_pPointer->setMotion([this](CCWlPointer* r, uint32_t timeMs, wl_fixed_t surface_x, wl_fixed_t surface_y) { + auto x = wl_fixed_to_double(surface_x); + auto y = wl_fixed_to_double(surface_y); + + m_vLastCoords = {x, y}; + + 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 SCALE = Vector2D{m_pLastSurface->screenBuffer->pixelSize.x / (m_pLastSurface->buffers[0]->pixelSize.x / m_pLastSurface->m_pMonitor->scale), + m_pLastSurface->screenBuffer->pixelSize.y / (m_pLastSurface->buffers[0]->pixelSize.y / m_pLastSurface->m_pMonitor->scale)}; + + const auto CLICKPOS = m_vLastCoords.floor() * SCALE; + + 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 = [](int i) -> std::string { + const char* DS = "0123456789ABCDEF"; + + std::string result = ""; + + result += DS[i / 16]; + result += DS[i % 16]; + + return result; + }; + + 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::lowest()) <= b && std::nextafter(a, std::numeric_limits::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); + s = std::round(s * 100); + + 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); + finish(); + break; + } + } + + finish(); + }); +} diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index 5a29d83..01e51e5 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -18,14 +18,17 @@ class CHyprpicker { std::mutex m_mtTickMutex; - wl_compositor* m_pCompositor = nullptr; - wl_display* m_pWLDisplay = nullptr; - wl_registry* m_pWLRegistry = nullptr; - wl_shm* m_pWLSHM = nullptr; - zwlr_layer_shell_v1* m_pLayerShell = nullptr; - zwlr_screencopy_manager_v1* m_pSCMgr = nullptr; - wp_cursor_shape_manager_v1* m_pCursorShape = nullptr; - wp_cursor_shape_device_v1* m_pCursorShapeDevice = nullptr; + SP m_pCompositor; + SP m_pRegistry; + SP m_pSHM; + SP m_pLayerShell; + SP m_pScreencopyMgr; + SP m_pCursorShapeMgr; + SP m_pCursorShapeDevice; + SP m_pSeat; + SP m_pKeyboard; + SP m_pPointer; + wl_display* m_pWLDisplay = nullptr; xkb_context* m_pXKBContext = nullptr; xkb_keymap* m_pXKBKeymap = nullptr; @@ -44,26 +47,22 @@ class CHyprpicker { std::vector> m_vMonitors; std::vector> m_vLayerSurfaces; - void createSeat(wl_seat*); - CLayerSurface* m_pLastSurface; Vector2D m_vLastCoords; void renderSurface(CLayerSurface*, bool forceInactive = false); - void createBuffer(SPoolBuffer*, int32_t, int32_t, uint32_t, uint32_t); - void destroyBuffer(SPoolBuffer*); int createPoolFile(size_t, std::string&); bool setCloexec(const int&); void recheckACK(); + void initKeyboard(); + void initMouse(); - void sendFrame(CLayerSurface*); + SP getBufferForLS(CLayerSurface*); - SPoolBuffer* getBufferForLS(CLayerSurface*); - - void convertBuffer(SPoolBuffer*); - void* convert24To32Buffer(SPoolBuffer*); + void convertBuffer(SP); + void* convert24To32Buffer(SP); void markDirty(); diff --git a/src/includes.hpp b/src/includes.hpp index 52d456b..4286f39 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -11,22 +11,12 @@ #include #include -#define class _class -#define namespace _namespace -#define static - -extern "C" { -#include "wlr-layer-shell-unstable-v1-protocol.h" -#include "wlr-screencopy-unstable-v1-protocol.h" -#include "xdg-shell-protocol.h" -#include "wp-cursor-shape-v1-protocol.h" -#include -#include -} - -#undef class -#undef namespace -#undef static +#include "protocols/cursor-shape-v1.hpp" +#include "protocols/fractional-scale-v1.hpp" +#include "protocols/wlr-layer-shell-unstable-v1.hpp" +#include "protocols/wlr-screencopy-unstable-v1.hpp" +#include "protocols/viewporter.hpp" +#include "protocols/wayland.hpp" #include #include @@ -45,3 +35,9 @@ extern "C" { #include #include #include + +#include +using namespace Hyprutils::Memory; + +#define SP CSharedPointer +#define WP CWeakPointer