core: migrate to hyprwayland-scanner

Additionally:
 - format
 - yeet clang-tidy
 - fixup clang-format
This commit is contained in:
Vaxry 2024-07-17 16:25:07 +02:00
parent f3a6e51d92
commit 3cbc90bf94
31 changed files with 518 additions and 751 deletions

View File

@ -1,114 +1,65 @@
--- ---
Language: Cpp Language: Cpp
Standard: Auto BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign AccessModifierOffset: -2
AlignArrayOfStructures: None AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None AlignConsecutiveMacros: true
AlignConsecutiveBitFields: Consecutive AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: None
AlignEscapedNewlines: Right AlignEscapedNewlines: Right
AlignOperands: DontAlign AlignOperands: false
AlignTrailingComments: true AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Empty AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false AllowShortCaseLabelsOnASingleLine: true
AllowShortEnumsOnASingleLine: true AllowShortFunctionsOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true BreakBeforeBraces: Attach
BinPackParameters: true BreakBeforeTernaryOperators: false
BitFieldColonSpacing: Both BreakConstructorInitializers: AfterColon
BreakAfterJavaFieldAnnotations: true ColumnLimit: 180
BreakBeforeBinaryOperators: NonAssignment CompactNamespaces: false
BreakBeforeConceptDeclarations: true
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakConstructorInitializersBeforeComma: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 0
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8 ExperimentalAutoDetectBinPacking: false
ContinuationIndentWidth: 4
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
FixNamespaceComments: false FixNamespaceComments: false
IncludeBlocks: Preserve IncludeBlocks: Preserve
IncludeIsMainRegex: (Test)?$
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: true IndentCaseLabels: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 4 IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
PPIndentWidth: -1
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left PointerAlignment: Left
QualifierAlignment: Leave ReflowComments: false
ReferenceAlignment: Pointer SortIncludes: false
ReflowComments: true SortUsingDeclarations: false
RemoveBracesLLVM: false
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCtorInitializerColon: true SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: true
SpaceInEmptyParentheses: false SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
SpacesInAngles: Never SpacesInAngles: false
SpacesInCStyleCastParentheses: false SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false SpacesInContainerLiterals: false
SpacesInContainerLiterals: true
SpacesInParentheses: false SpacesInParentheses: false
SpacesInSquareBrackets: false SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 4 TabWidth: 4
UseCRLF: false
UseTab: Never UseTab: Never
...
AllowShortEnumsOnASingleLine: false
BraceWrapping:
AfterEnum: false
AlignConsecutiveDeclarations: AcrossEmptyLines
NamespaceIndentation: All

View File

@ -1,6 +0,0 @@
---
Checks: '-*,clang-diagnostic-*,bugprone-*,cert-*,misc-*,modernize-*,performance-*,readability-*,hicpp-exception-baseclass,hicpp-avoid-goto,-clang-diagnostic-address-of-packed-member,-cert-dcl16-c,-cert-dcl21-cpp,-cert-err58-cpp,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-modernize-avoid-c-arrays,-modernize-concat-nested-namespaces,-modernize-raw-string-literal,-modernize-use-default-member-init,-modernize-use-nodiscard,-modernize-use-override,-modernize-use-trailing-return-type,-readability-else-after-return,-readability-identifier-naming,-readability-implicit-bool-cast,-readability-implicit-bool-conversion,-readability-magic-numbers,-readability-named-parameter,-readability-qualified-auto,-readability-redundant-access-specifiers,-readability-redundant-member-init,-readability-uppercase-literal-suffix'
WarningsAsErrors: '*'
HeaderFilterRegex: ''
FormatStyle: none
...

5
.gitignore vendored
View File

@ -19,6 +19,11 @@ result
*-protocol.h *-protocol.h
.ccls-cache .ccls-cache
protocols/*.hpp
protocols/*.cpp
.cache/
hyprctl/hyprctl hyprctl/hyprctl
gmon.out gmon.out

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.4) cmake_minimum_required(VERSION 3.12)
project(hyprpaper project(hyprpaper
DESCRIPTION "A blazing fast wayland wallpaper utility" DESCRIPTION "A blazing fast wayland wallpaper utility"
VERSION 0.7.0 VERSION 0.7.0
@ -36,35 +36,6 @@ execute_process(
# #
# #
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(hyprpaper 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(hyprpaper 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)
@ -72,16 +43,50 @@ add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-m
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols cairo pango pangocairo libjpeg libwebp hyprlang>=0.2.0 hyprutils>=0.2.0) pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols cairo pango pangocairo libjpeg libwebp hyprlang>=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(hyprpaper ${SRCFILES}) add_executable(hyprpaper ${SRCFILES})
protocol("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
protocol("stable/viewporter/viewporter.xml" "viewporter" false) pkg_get_variable(WAYLAND_CLIENT_DIR wayland-client pkgdatadir)
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false) message(STATUS "Found wayland-client at ${WAYLAND_CLIENT_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(hyprpaper 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_CLIENT_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
target_sources(hyprpaper PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
endfunction()
protocolWayland()
protocolNew("protocols" "wlr-layer-shell-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(hyprpaper PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") target_compile_definitions(hyprpaper PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
target_compile_definitions(hyprpaper PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") target_compile_definitions(hyprpaper PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"")

View File

@ -30,23 +30,22 @@ The development files of these packages need to be installed on the system for `
- libjpeg-turbo - libjpeg-turbo
- libwebp - libwebp
- hyprlang - hyprlang
- hyprutils
Please note hyprpaper > 0.5.0 depends on [hyprlang](https://github.com/hyprwm/hyprlang) which is new - hyprwayland-scanner
and might not be packaged for your distro yet. If that's the case, build and install it from source.
To install all of these in Fedora, run this command: To install all of these in Fedora, run this command:
``` ```
sudo dnf install wayland-devel wayland-protocols-devel hyprlang-devel pango-devel cairo-devel file-devel libglvnd-devel libglvnd-core-devel libjpeg-turbo-devel libwebp-devel gcc-c++ sudo dnf install wayland-devel wayland-protocols-devel hyprlang-devel pango-devel cairo-devel file-devel libglvnd-devel libglvnd-core-devel libjpeg-turbo-devel libwebp-devel gcc-c++ hyprutils-devel hyprwayland-scanner
``` ```
On Arch: On Arch:
``` ```
sudo pacman -S ninja gcc wayland-protocols libjpeg-turbo libwebp pango cairo pkgconf cmake libglvnd wayland sudo pacman -S ninja gcc wayland-protocols libjpeg-turbo libwebp pango cairo pkgconf cmake libglvnd wayland hyprutils hyprwayland-scanner hyprlang
``` ```
On OpenSUSE: On OpenSUSE:
``` ```
sudo zypper install ninja gcc-c++ wayland-protocols-devel Mesa-libGLESv3-devel file-devel sudo zypper install ninja gcc-c++ wayland-protocols-devel Mesa-libGLESv3-devel file-devel hyprutils-devel hyprwayland-scanner
``` ```
### Building ### Building

View File

@ -6,6 +6,47 @@
CHyprpaper::CHyprpaper() = default; CHyprpaper::CHyprpaper() = default;
static void handleGlobal(CCWlRegistry* registry, uint32_t name, const char* interface, uint32_t version) {
if (strcmp(interface, wl_compositor_interface.name) == 0) {
g_pHyprpaper->m_pCompositor = makeShared<CCWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wl_compositor_interface, 4));
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
g_pHyprpaper->m_pSHM = makeShared<CCWlShm>((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wl_shm_interface, 1));
} else if (strcmp(interface, wl_output_interface.name) == 0) {
g_pHyprpaper->m_mtTickMutex.lock();
const auto PMONITOR = g_pHyprpaper->m_vMonitors.emplace_back(std::make_unique<SMonitor>()).get();
PMONITOR->wayland_name = name;
PMONITOR->name = "";
PMONITOR->output = makeShared<CCWlOutput>((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wl_output_interface, 4));
PMONITOR->registerListeners();
g_pHyprpaper->m_mtTickMutex.unlock();
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
g_pHyprpaper->createSeat(makeShared<CCWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wl_seat_interface, 1)));
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
g_pHyprpaper->m_pLayerShell = makeShared<CCZwlrLayerShellV1>((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &zwlr_layer_shell_v1_interface, 1));
} else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0 && !g_pHyprpaper->m_bNoFractionalScale) {
g_pHyprpaper->m_pFractionalScale =
makeShared<CCWpFractionalScaleManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wp_fractional_scale_manager_v1_interface, 1));
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
g_pHyprpaper->m_pViewporter = makeShared<CCWpViewporter>((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wp_viewporter_interface, 1));
} else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {
g_pHyprpaper->m_pCursorShape =
makeShared<CCWpCursorShapeManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wp_cursor_shape_manager_v1_interface, 1));
}
}
static void handleGlobalRemove(CCWlRegistry* registry, uint32_t name) {
for (auto& m : g_pHyprpaper->m_vMonitors) {
if (m->wayland_name == name) {
Debug::log(LOG, "Destroying output %s", m->name.c_str());
g_pHyprpaper->clearWallpaperFromMonitor(m->name);
std::erase_if(g_pHyprpaper->m_vMonitors, [&](const auto& other) { return other->wayland_name == name; });
return;
}
}
}
void CHyprpaper::init() { void CHyprpaper::init() {
if (!lockSingleInstance()) { if (!lockSingleInstance()) {
@ -23,8 +64,9 @@ void CHyprpaper::init() {
} }
// run // run
wl_registry* registry = wl_display_get_registry(m_sDisplay); auto REGISTRY = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(m_sDisplay));
wl_registry_add_listener(registry, &Events::registryListener, nullptr); REGISTRY->setGlobal(::handleGlobal);
REGISTRY->setGlobalRemove(::handleGlobalRemove);
wl_display_roundtrip(m_sDisplay); wl_display_roundtrip(m_sDisplay);
@ -148,8 +190,28 @@ void CHyprpaper::recheckAllMonitors() {
} }
} }
void CHyprpaper::createSeat(wl_seat* pSeat) { void CHyprpaper::createSeat(SP<CCWlSeat> pSeat) {
wl_seat_add_listener(pSeat, &Events::seatListener, pSeat); m_pSeat = pSeat;
pSeat->setCapabilities([this](CCWlSeat* r, wl_seat_capability caps) {
if (caps & WL_SEAT_CAPABILITY_POINTER) {
m_pSeatPointer = makeShared<CCWlPointer>(m_pSeat->sendGetPointer());
if (!m_pCursorShape)
Debug::log(WARN, "No cursor-shape-v1 support from the compositor: cursor will be blank");
else
m_pSeatCursorShapeDevice = makeShared<CCWpCursorShapeDeviceV1>(m_pCursorShape->sendGetPointer(m_pSeatPointer->resource()));
m_pSeatPointer->setEnter([this](CCWlPointer* r, uint32_t serial, wl_resource* surface, wl_fixed_t x, wl_fixed_t y) {
if (!m_pCursorShape) {
m_pSeatPointer->sendSetCursor(serial, nullptr, 0, 0);
return;
}
m_pSeatCursorShapeDevice->sendSetShape(serial, wpCursorShapeDeviceV1Shape::WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
});
} else
Debug::log(LOG, "No pointer capability from the compositor");
});
} }
void CHyprpaper::recheckMonitor(SMonitor* pMonitor) { void CHyprpaper::recheckMonitor(SMonitor* pMonitor) {
@ -157,24 +219,7 @@ void CHyprpaper::recheckMonitor(SMonitor* pMonitor) {
if (pMonitor->wantsACK) { if (pMonitor->wantsACK) {
pMonitor->wantsACK = false; pMonitor->wantsACK = false;
zwlr_layer_surface_v1_ack_configure(pMonitor->pCurrentLayerSurface->pLayerSurface, pMonitor->configureSerial); pMonitor->pCurrentLayerSurface->pLayerSurface->sendAckConfigure(pMonitor->configureSerial);
if (!pMonitor->pCurrentLayerSurface->pCursorImg) {
int XCURSOR_SIZE = 24;
if (const auto CURSORSIZENV = getenv("XCURSOR_SIZE"); CURSORSIZENV) {
try {
if (XCURSOR_SIZE = std::stoi(CURSORSIZENV); XCURSOR_SIZE <= 0) {
throw std::exception();
}
} catch (...) {
Debug::log(WARN, "XCURSOR_SIZE environment variable is set incorrectly");
XCURSOR_SIZE = 24;
}
}
pMonitor->pCurrentLayerSurface->pCursorTheme = wl_cursor_theme_load(getenv("XCURSOR_THEME"), XCURSOR_SIZE * pMonitor->scale, m_sSHM);
pMonitor->pCurrentLayerSurface->pCursorImg = wl_cursor_theme_get_cursor(pMonitor->pCurrentLayerSurface->pCursorTheme, "left_ptr")->images[0];
}
} }
if (pMonitor->wantsReload) { if (pMonitor->wantsReload) {
@ -422,9 +467,9 @@ void CHyprpaper::createBuffer(SPoolBuffer* pBuffer, int32_t w, int32_t h, uint32
} }
const auto DATA = mmap(nullptr, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, FD, 0); const auto DATA = mmap(nullptr, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, FD, 0);
const auto POOL = wl_shm_create_pool(g_pHyprpaper->m_sSHM, FD, SIZE); auto POOL = makeShared<CCWlShmPool>(g_pHyprpaper->m_pSHM->sendCreatePool(FD, SIZE));
pBuffer->buffer = wl_shm_pool_create_buffer(POOL, 0, w, h, STRIDE, format); pBuffer->buffer = makeShared<CCWlBuffer>(POOL->sendCreateBuffer(0, w, h, STRIDE, format));
wl_shm_pool_destroy(POOL); POOL.reset();
close(FD); close(FD);
@ -437,7 +482,7 @@ void CHyprpaper::createBuffer(SPoolBuffer* pBuffer, int32_t w, int32_t h, uint32
} }
void CHyprpaper::destroyBuffer(SPoolBuffer* pBuffer) { void CHyprpaper::destroyBuffer(SPoolBuffer* pBuffer) {
wl_buffer_destroy(pBuffer->buffer); pBuffer->buffer.reset();
cairo_destroy(pBuffer->cairo); cairo_destroy(pBuffer->cairo);
cairo_surface_destroy(pBuffer->surface); cairo_surface_destroy(pBuffer->surface);
munmap(pBuffer->data, pBuffer->size); munmap(pBuffer->data, pBuffer->size);
@ -447,7 +492,10 @@ void CHyprpaper::destroyBuffer(SPoolBuffer* pBuffer) {
SPoolBuffer* CHyprpaper::getPoolBuffer(SMonitor* pMonitor, CWallpaperTarget* pWallpaperTarget) { SPoolBuffer* CHyprpaper::getPoolBuffer(SMonitor* pMonitor, CWallpaperTarget* pWallpaperTarget) {
const auto IT = std::find_if(m_vBuffers.begin(), m_vBuffers.end(), [&](const std::unique_ptr<SPoolBuffer>& el) { const auto IT = std::find_if(m_vBuffers.begin(), m_vBuffers.end(), [&](const std::unique_ptr<SPoolBuffer>& el) {
auto scale = std::round((pMonitor->pCurrentLayerSurface && pMonitor->pCurrentLayerSurface->pFractionalScaleInfo ? pMonitor->pCurrentLayerSurface->fScale : pMonitor->scale) * 120.0) / 120.0; auto scale =
std::round((pMonitor->pCurrentLayerSurface && pMonitor->pCurrentLayerSurface->pFractionalScaleInfo ? pMonitor->pCurrentLayerSurface->fScale : pMonitor->scale) *
120.0) /
120.0;
return el->target == pWallpaperTarget->m_szPath && vectorDeltaLessThan(el->pixelSize, pMonitor->size * scale, 1); return el->target == pWallpaperTarget->m_szPath && vectorDeltaLessThan(el->pixelSize, pMonitor->size * scale, 1);
}); });
@ -514,7 +562,8 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
origin.x = -(PWALLPAPERTARGET->m_vSize.x * scale - DIMENSIONS.x) / 2.0 / scale; origin.x = -(PWALLPAPERTARGET->m_vSize.x * scale - DIMENSIONS.x) / 2.0 / scale;
} }
Debug::log(LOG, "Image data for %s: %s at [%.2f, %.2f], scale: %.2f (original image size: [%i, %i])", pMonitor->name.c_str(), PWALLPAPERTARGET->m_szPath.c_str(), origin.x, origin.y, scale, (int)PWALLPAPERTARGET->m_vSize.x, (int)PWALLPAPERTARGET->m_vSize.y); Debug::log(LOG, "Image data for %s: %s at [%.2f, %.2f], scale: %.2f (original image size: [%i, %i])", pMonitor->name.c_str(), PWALLPAPERTARGET->m_szPath.c_str(), origin.x,
origin.y, scale, (int)PWALLPAPERTARGET->m_vSize.x, (int)PWALLPAPERTARGET->m_vSize.y);
cairo_scale(PCAIRO, scale, scale); cairo_scale(PCAIRO, scale, scale);
cairo_set_source_surface(PCAIRO, PWALLPAPERTARGET->m_pCairoSurface, origin.x, origin.y); cairo_set_source_surface(PCAIRO, PWALLPAPERTARGET->m_pCairoSurface, origin.x, origin.y);
@ -536,14 +585,16 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
Debug::log(LOG, "Splash color: %x", **PSPLASHCOLOR); Debug::log(LOG, "Splash color: %x", **PSPLASHCOLOR);
cairo_set_source_rgba(PCAIRO, ((**PSPLASHCOLOR >> 16) & 0xFF) / 255.0, ((**PSPLASHCOLOR >> 8) & 0xFF) / 255.0, (**PSPLASHCOLOR & 0xFF) / 255.0, ((**PSPLASHCOLOR >> 24) & 0xFF) / 255.0); cairo_set_source_rgba(PCAIRO, ((**PSPLASHCOLOR >> 16) & 0xFF) / 255.0, ((**PSPLASHCOLOR >> 8) & 0xFF) / 255.0, (**PSPLASHCOLOR & 0xFF) / 255.0,
((**PSPLASHCOLOR >> 24) & 0xFF) / 255.0);
cairo_text_extents_t textExtents; cairo_text_extents_t textExtents;
cairo_text_extents(PCAIRO, SPLASH.c_str(), &textExtents); cairo_text_extents(PCAIRO, SPLASH.c_str(), &textExtents);
cairo_move_to(PCAIRO, ((DIMENSIONS.x - textExtents.width * scale) / 2.0) / scale, ((DIMENSIONS.y * (100 - **PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale); cairo_move_to(PCAIRO, ((DIMENSIONS.x - textExtents.width * scale) / 2.0) / scale, ((DIMENSIONS.y * (100 - **PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale);
Debug::log(LOG, "Splash font size: %d, pos: %.2f, %.2f", FONTSIZE, (DIMENSIONS.x - textExtents.width) / 2.0 / scale, ((DIMENSIONS.y * (100 - **PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale); Debug::log(LOG, "Splash font size: %d, pos: %.2f, %.2f", FONTSIZE, (DIMENSIONS.x - textExtents.width) / 2.0 / scale,
((DIMENSIONS.y * (100 - **PSPLASHOFFSET)) / 100 - textExtents.height * scale) / scale);
cairo_show_text(PCAIRO, SPLASH.c_str()); cairo_show_text(PCAIRO, SPLASH.c_str());
@ -553,22 +604,21 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) {
cairo_restore(PCAIRO); cairo_restore(PCAIRO);
if (pMonitor->pCurrentLayerSurface) { if (pMonitor->pCurrentLayerSurface) {
wl_surface_attach(pMonitor->pCurrentLayerSurface->pSurface, PBUFFER->buffer, 0, 0); pMonitor->pCurrentLayerSurface->pSurface->sendAttach(PBUFFER->buffer.get(), 0, 0);
wl_surface_set_buffer_scale(pMonitor->pCurrentLayerSurface->pSurface, pMonitor->pCurrentLayerSurface->pFractionalScaleInfo ? 1 : pMonitor->scale); pMonitor->pCurrentLayerSurface->pSurface->sendSetBufferScale(pMonitor->pCurrentLayerSurface->pFractionalScaleInfo ? 1 : pMonitor->scale);
wl_surface_damage_buffer(pMonitor->pCurrentLayerSurface->pSurface, 0, 0, 0xFFFF, 0xFFFF); pMonitor->pCurrentLayerSurface->pSurface->sendDamageBuffer(0, 0, 0xFFFF, 0xFFFF);
// our wps are always opaque // our wps are always opaque
auto opaqueRegion = wl_compositor_create_region(g_pHyprpaper->m_sCompositor); auto opaqueRegion = makeShared<CCWlRegion>(g_pHyprpaper->m_pCompositor->sendCreateRegion());
wl_region_add(opaqueRegion, 0, 0, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y); opaqueRegion->sendAdd(0, 0, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y);
wl_surface_set_opaque_region(pMonitor->pCurrentLayerSurface->pSurface, opaqueRegion); pMonitor->pCurrentLayerSurface->pSurface->sendSetOpaqueRegion(opaqueRegion.get());
if (pMonitor->pCurrentLayerSurface->pFractionalScaleInfo) { if (pMonitor->pCurrentLayerSurface->pFractionalScaleInfo) {
Debug::log(LOG, "Submitting viewport dest size %ix%i for %x", static_cast<int>(std::round(pMonitor->size.x)), static_cast<int>(std::round(pMonitor->size.y)), pMonitor->pCurrentLayerSurface); Debug::log(LOG, "Submitting viewport dest size %ix%i for %x", static_cast<int>(std::round(pMonitor->size.x)), static_cast<int>(std::round(pMonitor->size.y)),
wp_viewport_set_destination(pMonitor->pCurrentLayerSurface->pViewport, static_cast<int>(std::round(pMonitor->size.x)), static_cast<int>(std::round(pMonitor->size.y))); pMonitor->pCurrentLayerSurface);
pMonitor->pCurrentLayerSurface->pViewport->sendSetDestination(static_cast<int>(std::round(pMonitor->size.x)), static_cast<int>(std::round(pMonitor->size.y)));
} }
wl_surface_commit(pMonitor->pCurrentLayerSurface->pSurface); pMonitor->pCurrentLayerSurface->pSurface->sendCommit();
wl_region_destroy(opaqueRegion);
} }
// check if we dont need to remove a wallpaper // check if we dont need to remove a wallpaper
@ -596,9 +646,7 @@ bool CHyprpaper::lockSingleInstance() {
if (errno != ESRCH) if (errno != ESRCH)
return false; return false;
} catch (std::exception& e) { } catch (std::exception& e) { ; }
;
}
} }
// create lockfile // create lockfile

View File

@ -2,7 +2,6 @@
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "defines.hpp" #include "defines.hpp"
#include "events/Events.hpp"
#include "helpers/MiscFunctions.hpp" #include "helpers/MiscFunctions.hpp"
#include "helpers/Monitor.hpp" #include "helpers/Monitor.hpp"
#include "helpers/PoolBuffer.hpp" #include "helpers/PoolBuffer.hpp"
@ -10,19 +9,30 @@
#include "render/WallpaperTarget.hpp" #include "render/WallpaperTarget.hpp"
#include <mutex> #include <mutex>
#include "protocols/cursor-shape-v1.hpp"
#include "protocols/fractional-scale-v1.hpp"
#include "protocols/linux-dmabuf-v1.hpp"
#include "protocols/viewporter.hpp"
#include "protocols/wayland.hpp"
#include "protocols/wlr-layer-shell-unstable-v1.hpp"
struct SWallpaperRenderData { struct SWallpaperRenderData {
bool contain = false; bool contain = false;
}; };
class CHyprpaper { class CHyprpaper {
public: public:
// important // important
wl_display* m_sDisplay; // assured wl_display* m_sDisplay = nullptr;
wl_compositor* m_sCompositor; // assured SP<CCWlCompositor> m_pCompositor;
wl_shm* m_sSHM; // assured SP<CCWlShm> m_pSHM;
zwlr_layer_shell_v1* m_sLayerShell = nullptr; // expected SP<CCZwlrLayerShellV1> m_pLayerShell;
wp_fractional_scale_manager_v1* m_sFractionalScale = nullptr; // will remain null if not bound SP<CCWpFractionalScaleManagerV1> m_pFractionalScale;
wp_viewporter* m_sViewporter = nullptr; // expected SP<CCWpViewporter> m_pViewporter;
SP<CCWlSeat> m_pSeat;
SP<CCWlPointer> m_pSeatPointer;
SP<CCWpCursorShapeDeviceV1> m_pSeatCursorShapeDevice;
SP<CCWpCursorShapeManagerV1> m_pCursorShape;
// init the utility // init the utility
CHyprpaper(); CHyprpaper();
@ -56,7 +66,7 @@ public:
void ensurePoolBuffersPresent(); void ensurePoolBuffersPresent();
SPoolBuffer* getPoolBuffer(SMonitor*, CWallpaperTarget*); SPoolBuffer* getPoolBuffer(SMonitor*, CWallpaperTarget*);
void unloadWallpaper(const std::string&); void unloadWallpaper(const std::string&);
void createSeat(wl_seat*); void createSeat(SP<CCWlSeat>);
bool lockSingleInstance(); // fails on multi-instance bool lockSingleInstance(); // fails on multi-instance
void unlockSingleInstance(); void unlockSingleInstance();
@ -64,7 +74,7 @@ public:
SMonitor* m_pLastMonitor = nullptr; SMonitor* m_pLastMonitor = nullptr;
private: private:
bool m_bShouldExit = false; bool m_bShouldExit = false;
}; };

View File

@ -1,6 +1,7 @@
#include "ConfigManager.hpp" #include "ConfigManager.hpp"
#include "../Hyprpaper.hpp" #include "../Hyprpaper.hpp"
#include <hyprutils/path/Path.hpp> #include <hyprutils/path/Path.hpp>
#include <filesystem>
static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) { static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
const std::string COMMAND = C; const std::string COMMAND = C;
@ -34,7 +35,8 @@ static Hyprlang::CParseResult handleWallpaper(const char* C, const char* V) {
return result; return result;
} }
if (std::find(g_pConfigManager->m_dRequestedPreloads.begin(), g_pConfigManager->m_dRequestedPreloads.end(), WALLPAPER) == g_pConfigManager->m_dRequestedPreloads.end() && !g_pHyprpaper->isPreloaded(WALLPAPER)) { if (std::find(g_pConfigManager->m_dRequestedPreloads.begin(), g_pConfigManager->m_dRequestedPreloads.end(), WALLPAPER) == g_pConfigManager->m_dRequestedPreloads.end() &&
!g_pHyprpaper->isPreloaded(WALLPAPER)) {
result.setError("wallpaper failed (not preloaded)"); result.setError("wallpaper failed (not preloaded)");
return result; return result;
} }
@ -189,8 +191,7 @@ void CConfigManager::parse() {
const auto ERROR = config->parse(); const auto ERROR = config->parse();
if (ERROR.error) if (ERROR.error)
std::cout << "Error in config: \n" std::cout << "Error in config: \n" << ERROR.getError() << "\n";
<< ERROR.getError() << "\n";
} }
std::string CConfigManager::getMainConfigPath() { std::string CConfigManager::getMainConfigPath() {

View File

@ -5,7 +5,7 @@
class CIPCSocket; class CIPCSocket;
class CConfigManager { class CConfigManager {
public: public:
// gets all the data from the config // gets all the data from the config
CConfigManager(); CConfigManager();
void parse(); void parse();
@ -16,7 +16,7 @@ public:
std::unique_ptr<Hyprlang::CConfig> config; std::unique_ptr<Hyprlang::CConfig> config;
private: private:
friend class CIPCSocket; friend class CIPCSocket;
}; };

View File

@ -9,23 +9,12 @@ void Debug::log(LogLevel level, const char* fmt, ...) {
std::string levelstr = ""; std::string levelstr = "";
switch (level) { switch (level) {
case LOG: case LOG: levelstr = "[LOG] "; break;
levelstr = "[LOG] "; case WARN: levelstr = "[WARN] "; break;
break; case ERR: levelstr = "[ERR] "; break;
case WARN: case CRIT: levelstr = "[CRITICAL] "; break;
levelstr = "[WARN] "; case INFO: levelstr = "[INFO] "; break;
break; default: break;
case ERR:
levelstr = "[ERR] ";
break;
case CRIT:
levelstr = "[CRITICAL] ";
break;
case INFO:
levelstr = "[INFO] ";
break;
default:
break;
} }
char buf[LOGMESSAGESIZE] = ""; char buf[LOGMESSAGESIZE] = "";

View File

@ -2,7 +2,6 @@
#include "includes.hpp" #include "includes.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
#include "helpers/Vector2D.hpp"
// git stuff // git stuff
#ifndef GIT_COMMIT_HASH #ifndef GIT_COMMIT_HASH
@ -17,3 +16,11 @@
#ifndef GIT_DIRTY #ifndef GIT_DIRTY
#define GIT_DIRTY "?" #define GIT_DIRTY "?"
#endif #endif
#include <hyprutils/math/Vector2D.hpp>
using namespace Hyprutils::Math;
#include <hyprutils/memory/WeakPtr.hpp>
using namespace Hyprutils::Memory;
#define SP Hyprutils::Memory::CSharedPointer
#define WP Hyprutils::Memory::CWeakPointer

View File

@ -1,164 +0,0 @@
#include "Events.hpp"
#include "../Hyprpaper.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) {
// ignored
}
void Events::mode(void* data, wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
const auto PMONITOR = (SMonitor*)data;
PMONITOR->size = Vector2D(width, height);
}
void Events::done(void* data, wl_output* wl_output) {
const auto PMONITOR = (SMonitor*)data;
PMONITOR->readyForLS = true;
std::lock_guard<std::mutex> lg(g_pHyprpaper->m_mtTickMutex);
if (g_pConfigManager) // don't tick if this is the first roundtrip
g_pHyprpaper->tick(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;
PMONITOR->name = name;
}
void Events::description(void* data, wl_output* wl_output, const char* description) {
const auto PMONITOR = (SMonitor*)data;
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
std::string m_description = description;
std::erase(m_description, ',');
PMONITOR->description = m_description;
}
void Events::handleCapabilities(void* data, wl_seat* wl_seat, uint32_t capabilities) {
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
wl_pointer_add_listener(wl_seat_get_pointer(wl_seat), &pointerListener, wl_seat);
}
}
void Events::handlePointerLeave(void* data, struct wl_pointer* wl_pointer, uint32_t serial, struct wl_surface* surface) {
// ignored
wl_surface_commit(surface);
g_pHyprpaper->m_pLastMonitor = nullptr;
}
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) {
// ignored
if (g_pHyprpaper->m_pLastMonitor) {
wl_surface_commit(g_pHyprpaper->m_pLastMonitor->pCurrentLayerSurface->pSurface);
}
}
void Events::handlePointerButton(void* data, struct wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t button_state) {
// ignored
}
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) {
for (auto& mon : g_pHyprpaper->m_vMonitors) {
if (mon->pCurrentLayerSurface->pSurface == surface) {
g_pHyprpaper->m_pLastMonitor = mon.get();
wl_surface_set_buffer_scale(mon->pCurrentLayerSurface->pCursorSurface, mon->scale);
wl_surface_attach(mon->pCurrentLayerSurface->pCursorSurface, wl_cursor_image_get_buffer(mon->pCurrentLayerSurface->pCursorImg), 0, 0);
wl_pointer_set_cursor(wl_pointer, serial, mon->pCurrentLayerSurface->pCursorSurface, mon->pCurrentLayerSurface->pCursorImg->hotspot_x / mon->scale, mon->pCurrentLayerSurface->pCursorImg->hotspot_y / mon->scale);
wl_surface_commit(mon->pCurrentLayerSurface->pCursorSurface);
}
}
}
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(width, height);
PLAYERSURFACE->m_pMonitor->wantsReload = true;
PLAYERSURFACE->m_pMonitor->configureSerial = serial;
PLAYERSURFACE->m_pMonitor->wantsACK = true;
PLAYERSURFACE->m_pMonitor->initialized = true;
Debug::log(LOG, "configure for %s", PLAYERSURFACE->m_pMonitor->name.c_str());
}
void Events::handleLSClosed(void* data, zwlr_layer_surface_v1* zwlr_layer_surface_v1) {
const auto PLAYERSURFACE = (CLayerSurface*)data;
for (auto& m : g_pHyprpaper->m_vMonitors) {
std::erase_if(m->layerSurfaces, [&](const auto& other) { return other.get() == PLAYERSURFACE; });
if (m->pCurrentLayerSurface == PLAYERSURFACE) {
if (m->layerSurfaces.empty()) {
m->pCurrentLayerSurface = nullptr;
} else {
m->pCurrentLayerSurface = m->layerSurfaces.begin()->get();
g_pHyprpaper->recheckMonitor(m.get());
}
}
}
}
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_pHyprpaper->m_sCompositor = (wl_compositor*)wl_registry_bind(registry, name, &wl_compositor_interface, 4);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
g_pHyprpaper->m_sSHM = (wl_shm*)wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, wl_output_interface.name) == 0) {
g_pHyprpaper->m_mtTickMutex.lock();
const auto PMONITOR = g_pHyprpaper->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_pHyprpaper->m_mtTickMutex.unlock();
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
g_pHyprpaper->createSeat((wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 1));
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
g_pHyprpaper->m_sLayerShell = (zwlr_layer_shell_v1*)wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
} else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0 && !g_pHyprpaper->m_bNoFractionalScale) {
g_pHyprpaper->m_sFractionalScale = (wp_fractional_scale_manager_v1*)wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, 1);
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
g_pHyprpaper->m_sViewporter = (wp_viewporter*)wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
}
}
void Events::handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name) {
for (auto& m : g_pHyprpaper->m_vMonitors) {
if (m->wayland_name == name) {
Debug::log(LOG, "Destroying output %s", m->name.c_str());
g_pHyprpaper->clearWallpaperFromMonitor(m->name);
std::erase_if(g_pHyprpaper->m_vMonitors, [&](const auto& other) { return other->wayland_name == name; });
return;
}
}
}
void Events::handlePreferredScale(void* data, wp_fractional_scale_v1* fractionalScaleInfo, uint32_t scale) {
const double SCALE = scale / 120.0;
CLayerSurface* const pLS = (CLayerSurface*)data;
Debug::log(LOG, "handlePreferredScale: %.2lf for %lx", SCALE, pLS);
if (pLS->fScale != SCALE) {
pLS->fScale = SCALE;
std::lock_guard<std::mutex> lg(g_pHyprpaper->m_mtTickMutex);
pLS->m_pMonitor->wantsReload = true;
g_pHyprpaper->tick(true);
}
}

View File

@ -1,51 +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 handleLSClosed(void *data, zwlr_layer_surface_v1 *zwlr_layer_surface_v1);
void handleGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version);
void handleGlobalRemove(void *data, struct 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 handlePreferredScale(void *data, wp_fractional_scale_v1 *wp_fractional_scale_v1, uint32_t scale);
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, .closed = handleLSClosed };
inline const struct wl_registry_listener registryListener = { .global = handleGlobal, .global_remove = handleGlobalRemove };
inline const wl_pointer_listener pointerListener = { .enter = handlePointerEnter, .leave = handlePointerLeave, .motion = handlePointerMotion, .button = handlePointerButton, .axis = handlePointerAxis };
inline const wl_seat_listener seatListener = { .capabilities = handleCapabilities };
inline const wp_fractional_scale_v1_listener scaleListener = { .preferred_scale = handlePreferredScale };
}

View File

@ -3,9 +3,10 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <filesystem>
class BmpHeader { class BmpHeader {
public: public:
unsigned char format[2]; unsigned char format[2];
uint32_t sizeOfFile; uint32_t sizeOfFile;
uint16_t reserved1; uint16_t reserved1;
@ -59,7 +60,7 @@ public:
if (!imageSize) if (!imageSize)
imageSize = sizeOfFile - dataOffset; imageSize = sizeOfFile - dataOffset;
if (imageSize != (width * height * numberOfBitPerPixel/8)) { if (imageSize != (width * height * numberOfBitPerPixel / 8)) {
Debug::log(ERR, "Unable to parse bitmap header: wrong image size"); Debug::log(ERR, "Unable to parse bitmap header: wrong image size");
exit(1); exit(1);
} }
@ -108,8 +109,8 @@ cairo_surface_t* BMP::createSurfaceFromBMP(const std::string& path) {
BmpHeader bitmapHeader(bitmapImageStream); BmpHeader bitmapHeader(bitmapImageStream);
cairo_format_t format = CAIRO_FORMAT_ARGB32; cairo_format_t format = CAIRO_FORMAT_ARGB32;
int stride = cairo_format_stride_for_width (format, bitmapHeader.width); int stride = cairo_format_stride_for_width(format, bitmapHeader.width);
unsigned char* imageData = (unsigned char*) malloc(bitmapHeader.height * stride); unsigned char* imageData = (unsigned char*)malloc(bitmapHeader.height * stride);
if (bitmapHeader.numberOfBitPerPixel == 24) if (bitmapHeader.numberOfBitPerPixel == 24)
convertRgbToArgb(bitmapImageStream, imageData, bitmapHeader.height * stride); convertRgbToArgb(bitmapImageStream, imageData, bitmapHeader.height * stride);

View File

@ -3,6 +3,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <filesystem>
cairo_surface_t* JPEG::createSurfaceFromJPEG(const std::string& path) { cairo_surface_t* JPEG::createSurfaceFromJPEG(const std::string& path) {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <string> #include <string>
#include "Vector2D.hpp" #include "../defines.hpp"
bool vectorDeltaLessThan(const Vector2D& a, const Vector2D& b, const float& delta); bool vectorDeltaLessThan(const Vector2D& a, const Vector2D& b, const float& delta);
bool vectorDeltaLessThan(const Vector2D& a, const Vector2D& b, const Vector2D& delta); bool vectorDeltaLessThan(const Vector2D& a, const Vector2D& b, const Vector2D& delta);

24
src/helpers/Monitor.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "Monitor.hpp"
#include "../Hyprpaper.hpp"
void SMonitor::registerListeners() {
output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { size = Vector2D(width, height); });
output->setDone([this](CCWlOutput* r) {
readyForLS = true;
std::lock_guard<std::mutex> lg(g_pHyprpaper->m_mtTickMutex);
if (g_pConfigManager) // don't tick if this is the first roundtrip
g_pHyprpaper->tick(true);
});
output->setScale([this](CCWlOutput* r, int32_t scale_) { scale = scale_; });
output->setName([this](CCWlOutput* r, const char* name_) { name = name_; });
output->setDescription([this](CCWlOutput* r, const char* desc_) {
std::string desc = desc_;
std::erase(desc, ',');
description = desc;
});
}

View File

@ -3,11 +3,12 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../render/LayerSurface.hpp" #include "../render/LayerSurface.hpp"
#include "PoolBuffer.hpp" #include "PoolBuffer.hpp"
#include "protocols/wayland.hpp"
struct SMonitor { struct SMonitor {
std::string name = ""; std::string name = "";
std::string description = ""; std::string description = "";
wl_output* output = nullptr; SP<CCWlOutput> output;
uint32_t wayland_name = 0; uint32_t wayland_name = 0;
Vector2D size; Vector2D size;
int scale; int scale;
@ -26,4 +27,6 @@ struct SMonitor {
std::vector<std::unique_ptr<CLayerSurface>> layerSurfaces; std::vector<std::unique_ptr<CLayerSurface>> layerSurfaces;
CLayerSurface* pCurrentLayerSurface = nullptr; CLayerSurface* pCurrentLayerSurface = nullptr;
void registerListeners();
}; };

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "protocols/wayland.hpp"
class CWallpaperTarget; class CWallpaperTarget;
struct SPoolBuffer { struct SPoolBuffer {
wl_buffer* buffer = nullptr; 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;

View File

@ -1,23 +0,0 @@
#include "Vector2D.hpp"
Vector2D::Vector2D(double xx, double yy) {
x = xx;
y = yy;
}
Vector2D::Vector2D() { x = 0; y = 0; }
Vector2D::~Vector2D() = default;
double Vector2D::normalize() {
// get max abs
const auto max = abs(x) > abs(y) ? abs(x) : abs(y);
x /= max;
y /= max;
return max;
}
Vector2D Vector2D::floor() const {
return {static_cast<int>(x), static_cast<int>(y)};
}

View File

@ -1,39 +0,0 @@
#pragma once
#include <cmath>
class Vector2D {
public:
Vector2D(double, double);
Vector2D();
~Vector2D();
double x = 0;
double y = 0;
// returns the scale
double normalize();
Vector2D operator+(const Vector2D a) const {
return Vector2D(this->x + a.x, this->y + a.y);
}
Vector2D operator-(const Vector2D a) const {
return Vector2D(this->x - a.x, this->y - a.y);
}
Vector2D operator*(const float a) const {
return Vector2D(this->x * a, this->y * a);
}
Vector2D operator/(const float a) const {
return Vector2D(this->x / a, this->y / a);
}
bool operator==(const Vector2D& a) const {
return a.x == x && a.y == y;
}
bool operator!=(const Vector2D& a) const {
return a.x != x || a.y != y;
}
Vector2D floor() const;
};

View File

@ -4,6 +4,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <filesystem>
#include <webp/decode.h> #include <webp/decode.h>
cairo_surface_t* WEBP::createSurfaceFromWEBP(const std::string& path) { cairo_surface_t* WEBP::createSurfaceFromWEBP(const std::string& path) {
@ -51,7 +52,6 @@ cairo_surface_t* WEBP::createSurfaceFromWEBP(const std::string& path) {
exit(1); exit(1);
} }
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
config.output.colorspace = MODE_bgrA; config.output.colorspace = MODE_bgrA;
#else #else
@ -80,5 +80,4 @@ cairo_surface_t* WEBP::createSurfaceFromWEBP(const std::string& path) {
WebPFreeDecBuffer(&config.output); WebPFreeDecBuffer(&config.output);
return cairoSurface; return cairoSurface;
} }

View File

@ -10,23 +10,6 @@
#include <pthread.h> #include <pthread.h>
#include <cmath> #include <cmath>
#define class _class
#define namespace _namespace
#define static
extern "C" {
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include "xdg-shell-protocol.h"
#include "fractional-scale-v1-protocol.h"
#include "viewporter-protocol.h"
#include <wayland-client.h>
#include <wayland-cursor.h>
}
#undef class
#undef namespace
#undef static
#include <GLES3/gl32.h> #include <GLES3/gl32.h>
#include <GLES3/gl3ext.h> #include <GLES3/gl3ext.h>
#include <cassert> #include <cassert>
@ -39,8 +22,3 @@ extern "C" {
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <algorithm>
#include <filesystem>
#include <thread>
#include <unordered_map>

View File

@ -12,6 +12,7 @@
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <pwd.h> #include <pwd.h>
#include <thread>
void CIPCSocket::initialize() { void CIPCSocket::initialize() {
std::thread([&]() { std::thread([&]() {

View File

@ -4,20 +4,18 @@
#include <mutex> #include <mutex>
class CIPCSocket { class CIPCSocket {
public: public:
void initialize(); void initialize();
bool mainThreadParseRequest(); bool mainThreadParseRequest();
private: private:
std::mutex m_mtRequestMutex; std::mutex m_mtRequestMutex;
std::string m_szRequest = ""; std::string m_szRequest = "";
std::string m_szReply = ""; std::string m_szReply = "";
bool m_bRequestReady = false; bool m_bRequestReady = false;
bool m_bReplyReady = false; bool m_bReplyReady = false;
}; };
inline std::unique_ptr<CIPCSocket> g_pIPCSocket; inline std::unique_ptr<CIPCSocket> g_pIPCSocket;

View File

@ -16,10 +16,10 @@ int main(int argc, char** argv, char** envp) {
noFractional = true; noFractional = true;
Debug::log(LOG, "Disabling fractional scaling support!"); Debug::log(LOG, "Disabling fractional scaling support!");
} else { } else {
std::cout << "Hyprpaper usage: hyprpaper [arg [...]].\n\nArguments:\n" << std::cout << "Hyprpaper usage: hyprpaper [arg [...]].\n\nArguments:\n"
"--help -h | Show this help message\n" << << "--help -h | Show this help message\n"
"--config -c | Specify config file to use\n" << << "--config -c | Specify config file to use\n"
"--no-fractional -n | Disable fractional scaling support\n"; << "--no-fractional -n | Disable fractional scaling support\n";
return 1; return 1;
} }
} }

View File

@ -5,62 +5,92 @@
CLayerSurface::CLayerSurface(SMonitor* pMonitor) { CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
m_pMonitor = pMonitor; m_pMonitor = pMonitor;
pSurface = wl_compositor_create_surface(g_pHyprpaper->m_sCompositor); pSurface = makeShared<CCWlSurface>(g_pHyprpaper->m_pCompositor->sendCreateSurface());
pCursorSurface = wl_compositor_create_surface(g_pHyprpaper->m_sCompositor);
if (!pSurface) { if (!pSurface) {
Debug::log(CRIT, "The compositor did not allow hyprpaper a surface!"); Debug::log(CRIT, "The compositor did not allow hyprpaper a surface!");
exit(1); exit(1);
} }
const auto PINPUTREGION = wl_compositor_create_region(g_pHyprpaper->m_sCompositor); const auto PINPUTREGION = makeShared<CCWlRegion>(g_pHyprpaper->m_pCompositor->sendCreateRegion());
if (!PINPUTREGION) { if (!PINPUTREGION) {
Debug::log(CRIT, "The compositor did not allow hyprpaper a region!"); Debug::log(CRIT, "The compositor did not allow hyprpaper a region!");
exit(1); exit(1);
} }
wl_surface_set_input_region(pSurface, PINPUTREGION); pSurface->sendSetInputRegion(PINPUTREGION.get());
pLayerSurface = zwlr_layer_shell_v1_get_layer_surface(g_pHyprpaper->m_sLayerShell, pSurface, pMonitor->output, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "hyprpaper"); pLayerSurface = makeShared<CCZwlrLayerSurfaceV1>(
g_pHyprpaper->m_pLayerShell->sendGetLayerSurface(pSurface->resource(), pMonitor->output->resource(), ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "hyprpaper"));
if (!pLayerSurface) { if (!pLayerSurface) {
Debug::log(CRIT, "The compositor did not allow hyprpaper a layersurface!"); Debug::log(CRIT, "The compositor did not allow hyprpaper a layersurface!");
exit(1); exit(1);
} }
zwlr_layer_surface_v1_set_size(pLayerSurface, 0, 0); pLayerSurface->sendSetSize(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); 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_set_exclusive_zone(pLayerSurface, -1); ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT));
zwlr_layer_surface_v1_add_listener(pLayerSurface, &Events::layersurfaceListener, this); pLayerSurface->sendSetExclusiveZone(-1);
wl_surface_commit(pSurface);
wl_region_destroy(PINPUTREGION); pLayerSurface->setConfigure([this](CCZwlrLayerSurfaceV1* r, uint32_t serial, uint32_t x, uint32_t y) {
m_pMonitor->size = Vector2D((double)x, (double)y);
m_pMonitor->wantsReload = true;
m_pMonitor->configureSerial = serial;
m_pMonitor->wantsACK = true;
m_pMonitor->initialized = true;
Debug::log(LOG, "configure for %s", m_pMonitor->name.c_str());
});
pLayerSurface->setClosed([this](CCZwlrLayerSurfaceV1* r) {
for (auto& m : g_pHyprpaper->m_vMonitors) {
std::erase_if(m->layerSurfaces, [&](const auto& other) { return other.get() == this; });
if (m->pCurrentLayerSurface == this) {
if (m->layerSurfaces.empty()) {
m->pCurrentLayerSurface = nullptr;
} else {
m->pCurrentLayerSurface = m->layerSurfaces.begin()->get();
g_pHyprpaper->recheckMonitor(m.get());
}
}
}
});
pSurface->sendCommit();
// fractional scale, if supported by the compositor // fractional scale, if supported by the compositor
if (g_pHyprpaper->m_sFractionalScale) { if (g_pHyprpaper->m_pFractionalScale && g_pHyprpaper->m_pViewporter) {
pFractionalScaleInfo = wp_fractional_scale_manager_v1_get_fractional_scale(g_pHyprpaper->m_sFractionalScale, pSurface); pFractionalScaleInfo = makeShared<CCWpFractionalScaleV1>(g_pHyprpaper->m_pFractionalScale->sendGetFractionalScale(pSurface->resource()));
wp_fractional_scale_v1_add_listener(pFractionalScaleInfo, &Events::scaleListener, this); pFractionalScaleInfo->setPreferredScale([this](CCWpFractionalScaleV1* r, uint32_t sc120) {
pViewport = wp_viewporter_get_viewport(g_pHyprpaper->m_sViewporter, pSurface); const double SCALE = sc120 / 120.0;
wl_surface_commit(pSurface);
Debug::log(LOG, "handlePreferredScale: %.2lf for %lx", SCALE, this);
if (fScale != SCALE) {
fScale = SCALE;
std::lock_guard<std::mutex> lg(g_pHyprpaper->m_mtTickMutex);
m_pMonitor->wantsReload = true;
g_pHyprpaper->tick(true);
} }
});
pViewport = makeShared<CCWpViewport>(g_pHyprpaper->m_pViewporter->sendGetViewport(pSurface->resource()));
pSurface->sendCommit();
} else
Debug::log(ERR, "No fractional-scale-v1 / wp-viewporter support from the compositor! fractional scaling will not work.");
wl_display_flush(g_pHyprpaper->m_sDisplay); wl_display_flush(g_pHyprpaper->m_sDisplay);
} }
CLayerSurface::~CLayerSurface() { CLayerSurface::~CLayerSurface() {
// hyprwayland-scanner will send the destructors automatically. Neat.
if (pCursorTheme) pLayerSurface.reset();
wl_cursor_theme_destroy(pCursorTheme); pFractionalScaleInfo.reset();
pViewport.reset();
if (g_pHyprpaper->m_sFractionalScale && pFractionalScaleInfo) { pSurface.reset();
wp_fractional_scale_v1_destroy(pFractionalScaleInfo);
wp_viewport_destroy(pViewport);
}
zwlr_layer_surface_v1_destroy(pLayerSurface);
wl_surface_destroy(pSurface);
wl_display_flush(g_pHyprpaper->m_sDisplay); wl_display_flush(g_pHyprpaper->m_sDisplay);
} }

View File

@ -1,24 +1,23 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "protocols/fractional-scale-v1.hpp"
#include "protocols/viewporter.hpp"
#include "protocols/wayland.hpp"
#include "protocols/wlr-layer-shell-unstable-v1.hpp"
struct SMonitor; struct SMonitor;
class CLayerSurface { class CLayerSurface {
public: public:
explicit CLayerSurface(SMonitor*); explicit CLayerSurface(SMonitor*);
~CLayerSurface(); ~CLayerSurface();
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;
SP<CCWpFractionalScaleV1> pFractionalScaleInfo = nullptr;
wl_cursor_theme* pCursorTheme = nullptr; SP<CCWpViewport> pViewport = nullptr;
wl_cursor_image* pCursorImg = nullptr;
wl_surface* pCursorSurface = nullptr;
wp_fractional_scale_v1* pFractionalScaleInfo = nullptr;
wp_viewport* pViewport = nullptr;
double fScale = 1.0; double fScale = 1.0;
}; };

View File

@ -1,5 +1,6 @@
#include "WallpaperTarget.hpp" #include "WallpaperTarget.hpp"
#include <chrono>
#include <magic.h> #include <magic.h>
CWallpaperTarget::~CWallpaperTarget() { CWallpaperTarget::~CWallpaperTarget() {
@ -25,7 +26,7 @@ void CWallpaperTarget::create(const std::string& path) {
CAIROSURFACE = WEBP::createSurfaceFromWEBP(path); CAIROSURFACE = WEBP::createSurfaceFromWEBP(path);
} else { } else {
// magic is slow, so only use it when no recognized extension is found // magic is slow, so only use it when no recognized extension is found
auto handle = magic_open(MAGIC_NONE|MAGIC_COMPRESS); auto handle = magic_open(MAGIC_NONE | MAGIC_COMPRESS);
magic_load(handle, nullptr); magic_load(handle, nullptr);
const auto type_str = std::string(magic_file(handle, path.c_str())); const auto type_str = std::string(magic_file(handle, path.c_str()));
@ -50,7 +51,7 @@ void CWallpaperTarget::create(const std::string& path) {
exit(1); exit(1);
} }
m_vSize = { cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE) }; m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)};
const auto MS = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - BEGINLOAD).count() / 1000.f; const auto MS = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - BEGINLOAD).count() / 1000.f;

View File

@ -6,8 +6,7 @@
#include "../helpers/Webp.hpp" #include "../helpers/Webp.hpp"
class CWallpaperTarget { class CWallpaperTarget {
public: public:
~CWallpaperTarget(); ~CWallpaperTarget();
void create(const std::string& path); void create(const std::string& path);