mirror of
https://github.com/hyprwm/hyprpicker.git
synced 2024-11-16 16:15:58 +01:00
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 <mihai@fufexan.net>
This commit is contained in:
parent
38fe668e58
commit
c9238d39f6
16 changed files with 671 additions and 768 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -16,6 +16,12 @@ result
|
||||||
*.o
|
*.o
|
||||||
*-protocol.c
|
*-protocol.c
|
||||||
*-protocol.h
|
*-protocol.h
|
||||||
|
|
||||||
|
protocols/*.cpp
|
||||||
|
protocols/*.hpp
|
||||||
|
|
||||||
|
.cache/
|
||||||
|
|
||||||
.ccls-cache
|
.ccls-cache
|
||||||
|
|
||||||
gmon.out
|
gmon.out
|
||||||
|
|
|
@ -38,40 +38,6 @@ execute_process(
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
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(.)
|
include_directories(.)
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
add_compile_options(-DWLR_USE_UNSTABLE)
|
add_compile_options(-DWLR_USE_UNSTABLE)
|
||||||
|
@ -97,19 +63,53 @@ pkg_check_modules(
|
||||||
pango
|
pango
|
||||||
pangocairo
|
pangocairo
|
||||||
libjpeg
|
libjpeg
|
||||||
hyprutils>=0.2.0)
|
hyprutils>=0.2.0
|
||||||
|
hyprwayland-scanner>=0.4.0)
|
||||||
|
|
||||||
file(GLOB_RECURSE SRCFILES "src/*.cpp")
|
file(GLOB_RECURSE SRCFILES "src/*.cpp")
|
||||||
|
|
||||||
add_executable(hyprpicker ${SRCFILES})
|
add_executable(hyprpicker ${SRCFILES})
|
||||||
|
|
||||||
protocol("protocols/wlr-layer-shell-unstable-v1.xml"
|
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||||
"wlr-layer-shell-unstable-v1" true)
|
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
|
||||||
protocol("protocols/wlr-screencopy-unstable-v1.xml"
|
pkg_get_variable(WAYLAND_SCANNER_DIR wayland-scanner pkgdatadir)
|
||||||
"wlr-screencopy-unstable-v1" true)
|
message(STATUS "Found wayland-scanner at ${WAYLAND_SCANNER_DIR}")
|
||||||
protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false)
|
|
||||||
protocol("staging/cursor-shape/cursor-shape-v1.xml" "wp-cursor-shape-v1" false)
|
function(protocolnew protoPath protoName external)
|
||||||
protocol("unstable/tablet/tablet-unstable-v2.xml" "tablet-unstable-v2" false)
|
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
|
target_compile_definitions(hyprpicker
|
||||||
PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
|
PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
|
||||||
|
|
36
flake.lock
36
flake.lock
|
@ -10,11 +10,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721324102,
|
"lastModified": 1727300645,
|
||||||
"narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=",
|
"narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprutils",
|
"repo": "hyprutils",
|
||||||
"rev": "962582a090bc233c4de9d9897f46794280288989",
|
"rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -23,13 +23,36 @@
|
||||||
"type": "github"
|
"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": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721138476,
|
"lastModified": 1727122398,
|
||||||
"narHash": "sha256-+W5eZOhhemLQxelojLxETfbFbc19NWawsXBlapYpqIA=",
|
"narHash": "sha256-o8VBeCWHBxGd4kVMceIayf5GApqTavJbTa44Xcg5Rrk=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "ad0b5eed1b6031efaed382844806550c3dcb4206",
|
"rev": "30439d93eb8b19861ccbe3e581abf97bdc91b093",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -42,6 +65,7 @@
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"hyprutils": "hyprutils",
|
"hyprutils": "hyprutils",
|
||||||
|
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
inputs.systems.follows = "systems";
|
inputs.systems.follows = "systems";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
hyprwayland-scanner = {
|
||||||
|
url = "github:hyprwm/hyprwayland-scanner";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.systems.follows = "systems";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
|
@ -36,6 +42,7 @@
|
||||||
default = self.overlays.hyprpicker;
|
default = self.overlays.hyprpicker;
|
||||||
hyprpicker = lib.composeManyExtensions [
|
hyprpicker = lib.composeManyExtensions [
|
||||||
inputs.hyprutils.overlays.default
|
inputs.hyprutils.overlays.default
|
||||||
|
inputs.hyprwayland-scanner.overlays.default
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
hyprpicker = prev.callPackage ./nix/default.nix {
|
hyprpicker = prev.callPackage ./nix/default.nix {
|
||||||
stdenv = prev.gcc13Stdenv;
|
stdenv = prev.gcc13Stdenv;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
cairo,
|
cairo,
|
||||||
fribidi,
|
fribidi,
|
||||||
hyprutils,
|
hyprutils,
|
||||||
|
hyprwayland-scanner,
|
||||||
libdatrie,
|
libdatrie,
|
||||||
libGL,
|
libGL,
|
||||||
libjpeg,
|
libjpeg,
|
||||||
|
@ -37,6 +38,7 @@ stdenv.mkDerivation {
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
cmake
|
cmake
|
||||||
|
hyprwayland-scanner
|
||||||
pkg-config
|
pkg-config
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -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<SMonitor>()).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<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 (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);
|
|
||||||
}
|
|
|
@ -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};
|
|
||||||
};
|
|
|
@ -1,12 +1,11 @@
|
||||||
#include "LayerSurface.hpp"
|
#include "LayerSurface.hpp"
|
||||||
|
|
||||||
#include "../events/Events.hpp"
|
|
||||||
#include "../hyprpicker.hpp"
|
#include "../hyprpicker.hpp"
|
||||||
|
|
||||||
CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
|
CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
|
||||||
m_pMonitor = pMonitor;
|
m_pMonitor = pMonitor;
|
||||||
|
|
||||||
pSurface = wl_compositor_create_surface(g_pHyprpicker->m_pCompositor);
|
pSurface = makeShared<CCWlSurface>(g_pHyprpicker->m_pCompositor->sendCreateSurface());
|
||||||
|
|
||||||
if (!pSurface) {
|
if (!pSurface) {
|
||||||
Debug::log(CRIT, "The compositor did not allow hyprpicker a surface!");
|
Debug::log(CRIT, "The compositor did not allow hyprpicker a surface!");
|
||||||
|
@ -14,7 +13,8 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
|
||||||
return;
|
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<CCZwlrLayerSurfaceV1>(
|
||||||
|
g_pHyprpicker->m_pLayerShell->sendGetLayerSurface(pSurface->resource(), pMonitor->output->resource(), ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "hyprpicker"));
|
||||||
|
|
||||||
if (!pLayerSurface) {
|
if (!pLayerSurface) {
|
||||||
Debug::log(CRIT, "The compositor did not allow hyprpicker a layersurface!");
|
Debug::log(CRIT, "The compositor did not allow hyprpicker a layersurface!");
|
||||||
|
@ -22,25 +22,63 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
zwlr_layer_surface_v1_set_size(pLayerSurface, 0, 0);
|
pLayerSurface->setConfigure([this](CCZwlrLayerSurfaceV1* r, uint32_t serial, uint32_t width, uint32_t height) {
|
||||||
zwlr_layer_surface_v1_set_anchor(
|
m_pMonitor->size = {(double)width, (double)height};
|
||||||
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);
|
ACKSerial = serial;
|
||||||
zwlr_layer_surface_v1_set_exclusive_zone(pLayerSurface, -1);
|
wantsACK = true;
|
||||||
zwlr_layer_surface_v1_set_keyboard_interactivity(pLayerSurface, true);
|
working = true;
|
||||||
zwlr_layer_surface_v1_add_listener(pLayerSurface, &Events::layersurfaceListener, this);
|
|
||||||
wl_surface_commit(pSurface);
|
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);
|
wl_display_flush(g_pHyprpicker->m_pWLDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
CLayerSurface::~CLayerSurface() {
|
CLayerSurface::~CLayerSurface() {
|
||||||
wl_surface_destroy(pSurface);
|
pLayerSurface.reset();
|
||||||
zwlr_layer_surface_v1_destroy(pLayerSurface);
|
pSurface.reset();
|
||||||
|
frameCallback.reset();
|
||||||
|
|
||||||
if (g_pHyprpicker->m_pWLDisplay)
|
if (g_pHyprpicker->m_pWLDisplay)
|
||||||
wl_display_flush(g_pHyprpicker->m_pWLDisplay);
|
wl_display_flush(g_pHyprpicker->m_pWLDisplay);
|
||||||
|
}
|
||||||
g_pHyprpicker->destroyBuffer(&buffers[0]);
|
|
||||||
g_pHyprpicker->destroyBuffer(&buffers[1]);
|
// this has to be a separate function because frameCallback.reset() will destroy the listener func
|
||||||
g_pHyprpicker->destroyBuffer(&screenBuffer);
|
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<CCWlCallback>(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<CCWlCallback>(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;
|
||||||
}
|
}
|
|
@ -10,20 +10,22 @@ class CLayerSurface {
|
||||||
CLayerSurface(SMonitor*);
|
CLayerSurface(SMonitor*);
|
||||||
~CLayerSurface();
|
~CLayerSurface();
|
||||||
|
|
||||||
|
void sendFrame();
|
||||||
|
void markDirty();
|
||||||
|
|
||||||
SMonitor* m_pMonitor = nullptr;
|
SMonitor* m_pMonitor = nullptr;
|
||||||
|
|
||||||
zwlr_layer_surface_v1* pLayerSurface = nullptr;
|
SP<CCZwlrLayerSurfaceV1> pLayerSurface = nullptr;
|
||||||
wl_surface* pSurface = nullptr;
|
SP<CCWlSurface> pSurface = nullptr;
|
||||||
wl_surface* pCursorSurface = nullptr;
|
|
||||||
|
|
||||||
bool wantsACK = false;
|
bool wantsACK = false;
|
||||||
uint32_t ACKSerial = 0;
|
uint32_t ACKSerial = 0;
|
||||||
bool working = false;
|
bool working = false;
|
||||||
|
|
||||||
int lastBuffer = 0;
|
int lastBuffer = 0;
|
||||||
SPoolBuffer buffers[2];
|
SP<SPoolBuffer> buffers[2];
|
||||||
|
|
||||||
SPoolBuffer screenBuffer;
|
SP<SPoolBuffer> screenBuffer;
|
||||||
uint32_t scflags = 0;
|
uint32_t scflags = 0;
|
||||||
uint32_t screenBufferFormat = 0;
|
uint32_t screenBufferFormat = 0;
|
||||||
|
|
||||||
|
@ -31,7 +33,5 @@ class CLayerSurface {
|
||||||
|
|
||||||
bool rendered = false;
|
bool rendered = false;
|
||||||
|
|
||||||
wl_callback* frame_callback = nullptr;
|
SP<CCWlCallback> frameCallback = nullptr;
|
||||||
|
|
||||||
wl_cursor_image* pCursorImg = nullptr;
|
|
||||||
};
|
};
|
119
src/helpers/Monitor.cpp
Normal file
119
src/helpers/Monitor.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include "Monitor.hpp"
|
||||||
|
#include "LayerSurface.hpp"
|
||||||
|
#include "../hyprpicker.hpp"
|
||||||
|
|
||||||
|
SMonitor::SMonitor(SP<CCWlOutput> 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<SPoolBuffer>(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<SPoolBuffer> newBuf = makeShared<SPoolBuffer>(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);
|
||||||
|
});
|
||||||
|
}
|
|
@ -4,9 +4,14 @@
|
||||||
#include <hyprutils/math/Vector2D.hpp>
|
#include <hyprutils/math/Vector2D.hpp>
|
||||||
using namespace Hyprutils::Math;
|
using namespace Hyprutils::Math;
|
||||||
|
|
||||||
|
class CLayerSurface;
|
||||||
|
|
||||||
struct SMonitor {
|
struct SMonitor {
|
||||||
|
SMonitor(SP<CCWlOutput> output_);
|
||||||
|
void initSCFrame();
|
||||||
|
|
||||||
std::string name = "";
|
std::string name = "";
|
||||||
wl_output* output = nullptr;
|
SP<CCWlOutput> output = nullptr;
|
||||||
uint32_t wayland_name = 0;
|
uint32_t wayland_name = 0;
|
||||||
Vector2D size;
|
Vector2D size;
|
||||||
int scale;
|
int scale;
|
||||||
|
@ -14,5 +19,6 @@ struct SMonitor {
|
||||||
|
|
||||||
bool ready = false;
|
bool ready = false;
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1* pSCFrame = nullptr;
|
CLayerSurface* pLS = nullptr;
|
||||||
|
SP<CCZwlrScreencopyFrameV1> pSCFrame = nullptr;
|
||||||
};
|
};
|
42
src/helpers/PoolBuffer.cpp
Normal file
42
src/helpers/PoolBuffer.cpp
Normal file
|
@ -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<CCWlShmPool>(g_pHyprpicker->m_pSHM->sendCreatePool(FD, SIZE));
|
||||||
|
buffer = makeShared<CCWlBuffer>(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);
|
||||||
|
}
|
|
@ -3,7 +3,10 @@
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
|
|
||||||
struct SPoolBuffer {
|
struct SPoolBuffer {
|
||||||
wl_buffer* buffer = nullptr;
|
SPoolBuffer(const Vector2D& size, uint32_t format, uint32_t stride);
|
||||||
|
~SPoolBuffer();
|
||||||
|
|
||||||
|
SP<CCWlBuffer> buffer = nullptr;
|
||||||
cairo_surface_t* surface = nullptr;
|
cairo_surface_t* surface = nullptr;
|
||||||
cairo_t* cairo = nullptr;
|
cairo_t* cairo = nullptr;
|
||||||
void* data = nullptr;
|
void* data = nullptr;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "hyprpicker.hpp"
|
#include "hyprpicker.hpp"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "events/Events.hpp"
|
|
||||||
|
|
||||||
void sigHandler(int sig) {
|
void sigHandler(int sig) {
|
||||||
g_pHyprpicker->m_vLayerSurfaces.clear();
|
g_pHyprpicker->m_vLayerSurfaces.clear();
|
||||||
|
@ -22,22 +21,76 @@ void CHyprpicker::init() {
|
||||||
|
|
||||||
signal(SIGTERM, sigHandler);
|
signal(SIGTERM, sigHandler);
|
||||||
|
|
||||||
m_pWLRegistry = wl_display_get_registry(m_pWLDisplay);
|
m_pRegistry = makeShared<CCWlRegistry>((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<CCWlCompositor>((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<CCWlShm>((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<SMonitor>(
|
||||||
|
makeShared<CCWlOutput>((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<CCZwlrLayerShellV1>((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<CCWlSeat>((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<CCWlPointer>(m_pSeat->sendGetPointer());
|
||||||
|
initMouse();
|
||||||
|
if (m_pCursorShapeMgr)
|
||||||
|
m_pCursorShapeDevice = makeShared<CCWpCursorShapeDeviceV1>(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<CCWlKeyboard>(m_pSeat->sendGetKeyboard());
|
||||||
|
initKeyboard();
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
m_pKeyboard.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) {
|
||||||
|
m_pScreencopyMgr =
|
||||||
|
makeShared<CCZwlrScreencopyManagerV1>((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<CCWpCursorShapeManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_cursor_shape_manager_v1_interface, 1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
wl_display_roundtrip(m_pWLDisplay);
|
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) {
|
for (auto& m : m_vMonitors) {
|
||||||
m_vLayerSurfaces.emplace_back(std::make_unique<CLayerSurface>(m.get()));
|
m_vLayerSurfaces.emplace_back(std::make_unique<CLayerSurface>(m.get()));
|
||||||
|
|
||||||
m_pLastSurface = m_vLayerSurfaces.back().get();
|
m_pLastSurface = m_vLayerSurfaces.back().get();
|
||||||
|
|
||||||
m->pSCFrame = zwlr_screencopy_manager_v1_capture_output(m_pSCMgr, false, m->output);
|
m->pSCFrame = makeShared<CCZwlrScreencopyFrameV1>(m_pScreencopyMgr->sendCaptureOutput(false, m->output->resource()));
|
||||||
|
m->pLS = m_vLayerSurfaces.back().get();
|
||||||
zwlr_screencopy_frame_v1_add_listener(m->pSCFrame, &Events::screencopyListener, m_pLastSurface);
|
m->initSCFrame();
|
||||||
|
|
||||||
m_pLastSurface->pCursorSurface = wl_compositor_create_surface(m_pCompositor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_display_roundtrip(m_pWLDisplay);
|
wl_display_roundtrip(m_pWLDisplay);
|
||||||
|
@ -56,6 +109,19 @@ void CHyprpicker::finish(int code) {
|
||||||
m_vLayerSurfaces.clear();
|
m_vLayerSurfaces.clear();
|
||||||
|
|
||||||
if (m_pWLDisplay) {
|
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);
|
wl_display_disconnect(m_pWLDisplay);
|
||||||
m_pWLDisplay = nullptr;
|
m_pWLDisplay = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -65,29 +131,13 @@ void CHyprpicker::finish(int code) {
|
||||||
|
|
||||||
void CHyprpicker::recheckACK() {
|
void CHyprpicker::recheckACK() {
|
||||||
for (auto& ls : m_vLayerSurfaces) {
|
for (auto& ls : m_vLayerSurfaces) {
|
||||||
if (ls->wantsACK && ls->screenBuffer.buffer) {
|
if (ls->wantsACK) {
|
||||||
ls->wantsACK = false;
|
ls->wantsACK = false;
|
||||||
zwlr_layer_surface_v1_ack_configure(ls->pLayerSurface, ls->ACKSerial);
|
ls->pLayerSurface->sendAckConfigure(ls->ACKSerial);
|
||||||
|
|
||||||
if (!ls->buffers[0].buffer) {
|
if (!ls->buffers[0] || ls->buffers[0]->pixelSize != ls->m_pMonitor->size * ls->m_pMonitor->scale) {
|
||||||
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->buffers[0] = makeShared<SPoolBuffer>(ls->m_pMonitor->size * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4);
|
||||||
ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4);
|
ls->buffers[1] = makeShared<SPoolBuffer>(ls->m_pMonitor->size * 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];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,30 +147,23 @@ void CHyprpicker::recheckACK() {
|
||||||
|
|
||||||
void CHyprpicker::markDirty() {
|
void CHyprpicker::markDirty() {
|
||||||
for (auto& ls : m_vLayerSurfaces) {
|
for (auto& ls : m_vLayerSurfaces) {
|
||||||
if (ls->frame_callback)
|
if (ls->frameCallback)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ls->frame_callback = wl_surface_frame(ls->pSurface);
|
ls->markDirty();
|
||||||
wl_callback_add_listener(ls->frame_callback, &Events::frameListener, ls.get());
|
|
||||||
wl_surface_commit(ls->pSurface);
|
|
||||||
|
|
||||||
ls->dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SPoolBuffer* CHyprpicker::getBufferForLS(CLayerSurface* pLS) {
|
SP<SPoolBuffer> CHyprpicker::getBufferForLS(CLayerSurface* pLS) {
|
||||||
SPoolBuffer* returns = nullptr;
|
SP<SPoolBuffer> returns = nullptr;
|
||||||
|
|
||||||
for (auto i = 0; i < 2; ++i) {
|
for (auto i = 0; i < 2; ++i) {
|
||||||
if (pLS->buffers[i].busy)
|
if (!pLS->buffers[i] || pLS->buffers[i]->busy)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
returns = &pLS->buffers[i];
|
returns = pLS->buffers[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!returns)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return returns;
|
return returns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,57 +210,7 @@ int CHyprpicker::createPoolFile(size_t size, std::string& name) {
|
||||||
return FD;
|
return FD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprpicker::createBuffer(SPoolBuffer* pBuffer, int32_t w, int32_t h, uint32_t format, uint32_t stride) {
|
void CHyprpicker::convertBuffer(SP<SPoolBuffer> pBuffer) {
|
||||||
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) {
|
|
||||||
switch (pBuffer->format) {
|
switch (pBuffer->format) {
|
||||||
case WL_SHM_FORMAT_ARGB8888:
|
case WL_SHM_FORMAT_ARGB8888:
|
||||||
case WL_SHM_FORMAT_XRGB8888: break;
|
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!
|
// Mallocs a new buffer, which needs to be free'd!
|
||||||
void* CHyprpicker::convert24To32Buffer(SPoolBuffer* pBuffer) {
|
void* CHyprpicker::convert24To32Buffer(SP<SPoolBuffer> pBuffer) {
|
||||||
uint8_t* newBuffer = (uint8_t*)malloc((size_t)pBuffer->pixelSize.x * pBuffer->pixelSize.y * 4);
|
uint8_t* newBuffer = (uint8_t*)malloc((size_t)pBuffer->pixelSize.x * pBuffer->pixelSize.y * 4);
|
||||||
int newBufferStride = pBuffer->pixelSize.x * 4;
|
int newBufferStride = pBuffer->pixelSize.x * 4;
|
||||||
uint8_t* oldBuffer = (uint8_t*)pBuffer->data;
|
uint8_t* oldBuffer = (uint8_t*)pBuffer->data;
|
||||||
|
@ -325,8 +318,8 @@ void* CHyprpicker::convert24To32Buffer(SPoolBuffer* pBuffer) {
|
||||||
void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
|
void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
|
||||||
const auto PBUFFER = getBufferForLS(pSurface);
|
const auto PBUFFER = getBufferForLS(pSurface);
|
||||||
|
|
||||||
if (!PBUFFER || !pSurface->screenBuffer.buffer) {
|
if (!PBUFFER || !pSurface->screenBuffer) {
|
||||||
Debug::log(ERR, PBUFFER ? "renderSurface: pSurface->screenBuffer.buffer null" : "renderSurface: PBUFFER null");
|
// Debug::log(ERR, PBUFFER ? "renderSurface: pSurface->screenBuffer null" : "renderSurface: PBUFFER null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,13 +338,13 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
|
||||||
cairo_fill(PCAIRO);
|
cairo_fill(PCAIRO);
|
||||||
|
|
||||||
if (pSurface == g_pHyprpicker->m_pLastSurface && !forceInactive) {
|
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{
|
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.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.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 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_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR);
|
||||||
cairo_matrix_t matrixPre;
|
cairo_matrix_t matrixPre;
|
||||||
cairo_matrix_init_identity(&matrixPre);
|
cairo_matrix_init_identity(&matrixPre);
|
||||||
|
@ -394,7 +387,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
|
||||||
cairo_restore(PCAIRO);
|
cairo_restore(PCAIRO);
|
||||||
cairo_save(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_pattern_set_filter(PATTERN, CAIRO_FILTER_NEAREST);
|
||||||
cairo_matrix_t matrix;
|
cairo_matrix_t matrix;
|
||||||
cairo_matrix_init_identity(&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_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);
|
cairo_fill(PCAIRO);
|
||||||
} else {
|
} else {
|
||||||
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 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_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR);
|
||||||
cairo_matrix_t matrixPre;
|
cairo_matrix_t matrixPre;
|
||||||
cairo_matrix_init_identity(&matrixPre);
|
cairo_matrix_init_identity(&matrixPre);
|
||||||
|
@ -434,7 +427,7 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
|
||||||
cairo_pattern_destroy(PATTERNPRE);
|
cairo_pattern_destroy(PATTERNPRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendFrame(pSurface);
|
pSurface->sendFrame();
|
||||||
cairo_destroy(PCAIRO);
|
cairo_destroy(PCAIRO);
|
||||||
cairo_surface_destroy(PBUFFER->surface);
|
cairo_surface_destroy(PBUFFER->surface);
|
||||||
|
|
||||||
|
@ -445,26 +438,222 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
|
||||||
pSurface->rendered = true;
|
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) {
|
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 {
|
struct pixel {
|
||||||
unsigned char blue;
|
unsigned char blue;
|
||||||
unsigned char green;
|
unsigned char green;
|
||||||
unsigned char red;
|
unsigned char red;
|
||||||
unsigned char alpha;
|
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};
|
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<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);
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -18,14 +18,17 @@ class CHyprpicker {
|
||||||
|
|
||||||
std::mutex m_mtTickMutex;
|
std::mutex m_mtTickMutex;
|
||||||
|
|
||||||
wl_compositor* m_pCompositor = nullptr;
|
SP<CCWlCompositor> m_pCompositor;
|
||||||
|
SP<CCWlRegistry> m_pRegistry;
|
||||||
|
SP<CCWlShm> m_pSHM;
|
||||||
|
SP<CCZwlrLayerShellV1> m_pLayerShell;
|
||||||
|
SP<CCZwlrScreencopyManagerV1> m_pScreencopyMgr;
|
||||||
|
SP<CCWpCursorShapeManagerV1> m_pCursorShapeMgr;
|
||||||
|
SP<CCWpCursorShapeDeviceV1> m_pCursorShapeDevice;
|
||||||
|
SP<CCWlSeat> m_pSeat;
|
||||||
|
SP<CCWlKeyboard> m_pKeyboard;
|
||||||
|
SP<CCWlPointer> m_pPointer;
|
||||||
wl_display* m_pWLDisplay = 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;
|
|
||||||
|
|
||||||
xkb_context* m_pXKBContext = nullptr;
|
xkb_context* m_pXKBContext = nullptr;
|
||||||
xkb_keymap* m_pXKBKeymap = nullptr;
|
xkb_keymap* m_pXKBKeymap = nullptr;
|
||||||
|
@ -44,26 +47,22 @@ class CHyprpicker {
|
||||||
std::vector<std::unique_ptr<SMonitor>> m_vMonitors;
|
std::vector<std::unique_ptr<SMonitor>> m_vMonitors;
|
||||||
std::vector<std::unique_ptr<CLayerSurface>> m_vLayerSurfaces;
|
std::vector<std::unique_ptr<CLayerSurface>> m_vLayerSurfaces;
|
||||||
|
|
||||||
void createSeat(wl_seat*);
|
|
||||||
|
|
||||||
CLayerSurface* m_pLastSurface;
|
CLayerSurface* m_pLastSurface;
|
||||||
|
|
||||||
Vector2D m_vLastCoords;
|
Vector2D m_vLastCoords;
|
||||||
|
|
||||||
void renderSurface(CLayerSurface*, bool forceInactive = false);
|
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&);
|
int createPoolFile(size_t, std::string&);
|
||||||
bool setCloexec(const int&);
|
bool setCloexec(const int&);
|
||||||
void recheckACK();
|
void recheckACK();
|
||||||
|
void initKeyboard();
|
||||||
|
void initMouse();
|
||||||
|
|
||||||
void sendFrame(CLayerSurface*);
|
SP<SPoolBuffer> getBufferForLS(CLayerSurface*);
|
||||||
|
|
||||||
SPoolBuffer* getBufferForLS(CLayerSurface*);
|
void convertBuffer(SP<SPoolBuffer>);
|
||||||
|
void* convert24To32Buffer(SP<SPoolBuffer>);
|
||||||
void convertBuffer(SPoolBuffer*);
|
|
||||||
void* convert24To32Buffer(SPoolBuffer*);
|
|
||||||
|
|
||||||
void markDirty();
|
void markDirty();
|
||||||
|
|
||||||
|
|
|
@ -11,22 +11,12 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define class _class
|
#include "protocols/cursor-shape-v1.hpp"
|
||||||
#define namespace _namespace
|
#include "protocols/fractional-scale-v1.hpp"
|
||||||
#define static
|
#include "protocols/wlr-layer-shell-unstable-v1.hpp"
|
||||||
|
#include "protocols/wlr-screencopy-unstable-v1.hpp"
|
||||||
extern "C" {
|
#include "protocols/viewporter.hpp"
|
||||||
#include "wlr-layer-shell-unstable-v1-protocol.h"
|
#include "protocols/wayland.hpp"
|
||||||
#include "wlr-screencopy-unstable-v1-protocol.h"
|
|
||||||
#include "xdg-shell-protocol.h"
|
|
||||||
#include "wp-cursor-shape-v1-protocol.h"
|
|
||||||
#include <wayland-client.h>
|
|
||||||
#include <wayland-cursor.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef class
|
|
||||||
#undef namespace
|
|
||||||
#undef static
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
@ -45,3 +35,9 @@ extern "C" {
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <hyprutils/memory/WeakPtr.hpp>
|
||||||
|
using namespace Hyprutils::Memory;
|
||||||
|
|
||||||
|
#define SP CSharedPointer
|
||||||
|
#define WP CWeakPointer
|
||||||
|
|
Loading…
Reference in a new issue