mirror of
https://github.com/hyprwm/Hyprland
synced 2025-12-20 02:30:03 +01:00
desktop: rewrite reserved area handling + improve tests (#12383)
This commit is contained in:
parent
d5c52ef58e
commit
9264436f35
32 changed files with 818 additions and 413 deletions
1
.github/actions/setup_base/action.yml
vendored
1
.github/actions/setup_base/action.yml
vendored
|
|
@ -24,6 +24,7 @@ runs:
|
|||
glm \
|
||||
glslang \
|
||||
go \
|
||||
gtest \
|
||||
hyprlang \
|
||||
hyprcursor \
|
||||
jq \
|
||||
|
|
|
|||
1
.github/workflows/nix-ci.yml
vendored
1
.github/workflows/nix-ci.yml
vendored
|
|
@ -25,6 +25,5 @@ jobs:
|
|||
|
||||
test:
|
||||
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
|
||||
needs: hyprland
|
||||
uses: ./.github/workflows/nix-test.yml
|
||||
secrets: inherit
|
||||
|
|
|
|||
101
CMakeLists.txt
101
CMakeLists.txt
|
|
@ -79,9 +79,11 @@ message(
|
|||
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
||||
message(STATUS "Configuring Hyprland in Debug with CMake")
|
||||
add_compile_definitions(HYPRLAND_DEBUG)
|
||||
set(BUILD_TESTING ON)
|
||||
else()
|
||||
add_compile_options(-O3)
|
||||
message(STATUS "Configuring Hyprland in Release with CMake")
|
||||
set(BUILD_TESTING OFF)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}")
|
||||
|
|
@ -241,7 +243,7 @@ set(LIBINPUT_MINIMUM_VERSION 1.28)
|
|||
pkg_check_modules(
|
||||
deps
|
||||
REQUIRED
|
||||
IMPORTED_TARGET
|
||||
IMPORTED_TARGET GLOBAL
|
||||
xkbcommon>=${XKBCOMMMON_MINIMUM_VERSION}
|
||||
uuid
|
||||
wayland-server>=${WAYLAND_SERVER_MINIMUM_VERSION}
|
||||
|
|
@ -261,6 +263,8 @@ pkg_check_modules(
|
|||
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
|
||||
|
||||
file(GLOB_RECURSE SRCFILES "src/*.cpp")
|
||||
get_filename_component(FULL_MAIN_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp ABSOLUTE)
|
||||
list(REMOVE_ITEM SRCFILES "${FULL_MAIN_PATH}")
|
||||
|
||||
set(TRACY_CPP_FILES "")
|
||||
if(USE_TRACY)
|
||||
|
|
@ -268,7 +272,12 @@ if(USE_TRACY)
|
|||
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
|
||||
endif()
|
||||
|
||||
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
|
||||
add_library(hyprland_lib STATIC ${SRCFILES})
|
||||
add_executable(Hyprland src/main.cpp ${TRACY_CPP_FILES})
|
||||
target_link_libraries(Hyprland hyprland_lib)
|
||||
|
||||
target_include_directories(hyprland_lib PUBLIC ${deps_INCLUDE_DIRS})
|
||||
target_include_directories(Hyprland PUBLIC ${deps_INCLUDE_DIRS})
|
||||
|
||||
set(USE_GPROF OFF)
|
||||
|
||||
|
|
@ -278,8 +287,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
|||
if(WITH_ASAN)
|
||||
message(STATUS "Enabling ASan")
|
||||
|
||||
target_link_libraries(Hyprland asan)
|
||||
target_compile_options(Hyprland PUBLIC -fsanitize=address)
|
||||
target_link_libraries(hyprland_lib PUBLIC asan)
|
||||
target_compile_options(hyprland_lib PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
|
||||
if(USE_TRACY)
|
||||
|
|
@ -289,7 +298,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
|
|||
option(TRACY_ON_DEMAND "" ON)
|
||||
add_subdirectory(subprojects/tracy)
|
||||
|
||||
target_link_libraries(Hyprland Tracy::TracyClient)
|
||||
target_link_libraries(hyprland_lib PUBLIC Tracy::TracyClient)
|
||||
|
||||
if(USE_TRACY_GPU)
|
||||
message(STATUS "Tracy GPU Profiling is turned on")
|
||||
|
|
@ -314,19 +323,19 @@ endif()
|
|||
include(CheckLibraryExists)
|
||||
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
|
||||
if(HAVE_LIBEXECINFO)
|
||||
target_link_libraries(Hyprland execinfo)
|
||||
target_link_libraries(hyprland_lib PUBLIC execinfo)
|
||||
endif()
|
||||
|
||||
check_include_file("sys/timerfd.h" HAS_TIMERFD)
|
||||
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
|
||||
if(NOT HAS_TIMERFD AND epoll_FOUND)
|
||||
target_link_libraries(Hyprland PkgConfig::epoll)
|
||||
target_link_libraries(hyprland_lib PUBLIC PkgConfig::epoll)
|
||||
endif()
|
||||
|
||||
check_include_file("sys/inotify.h" HAS_INOTIFY)
|
||||
pkg_check_modules(inotify IMPORTED_TARGET libinotify)
|
||||
if(NOT HAS_INOTIFY AND inotify_FOUND)
|
||||
target_link_libraries(Hyprland PkgConfig::inotify)
|
||||
target_link_libraries(hyprland_lib PUBLIC PkgConfig::inotify)
|
||||
endif()
|
||||
|
||||
if(NO_XWAYLAND)
|
||||
|
|
@ -352,7 +361,7 @@ else()
|
|||
string(JOIN ", " PKGCONFIG_XWAYLAND_DEPENDENCIES ${XWAYLAND_DEPENDENCIES})
|
||||
string(PREPEND PKGCONFIG_XWAYLAND_DEPENDENCIES ", ")
|
||||
|
||||
target_link_libraries(Hyprland PkgConfig::xdeps)
|
||||
target_link_libraries(hyprland_lib PUBLIC PkgConfig::xdeps)
|
||||
endif()
|
||||
|
||||
configure_file(hyprland.pc.in hyprland.pc @ONLY)
|
||||
|
|
@ -381,31 +390,38 @@ if(CMAKE_DISABLE_PRECOMPILE_HEADERS)
|
|||
message(STATUS "Not using precompiled headers")
|
||||
else()
|
||||
message(STATUS "Setting precompiled headers")
|
||||
target_precompile_headers(Hyprland PRIVATE
|
||||
target_precompile_headers(hyprland_lib PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
|
||||
endif()
|
||||
|
||||
message(STATUS "Setting link libraries")
|
||||
|
||||
target_link_libraries(
|
||||
Hyprland
|
||||
${LIBRT}
|
||||
hyprland_lib
|
||||
PUBLIC
|
||||
PkgConfig::aquamarine_dep
|
||||
PkgConfig::hyprlang_dep
|
||||
PkgConfig::hyprutils_dep
|
||||
PkgConfig::hyprcursor_dep
|
||||
PkgConfig::hyprgraphics_dep
|
||||
PkgConfig::deps)
|
||||
PkgConfig::deps
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
Hyprland
|
||||
${LIBRT}
|
||||
hyprland_lib)
|
||||
if(udis_dep_FOUND)
|
||||
target_link_libraries(Hyprland PkgConfig::udis_dep)
|
||||
target_link_libraries(hyprland_lib PUBLIC PkgConfig::udis_dep)
|
||||
elseif(NOT("${udis_nopc}" MATCHES "udis_nopc-NOTFOUND"))
|
||||
target_link_libraries(Hyprland ${udis_nopc})
|
||||
target_link_libraries(hyprland_lib PUBLIC ${udis_nopc})
|
||||
else()
|
||||
target_link_libraries(Hyprland libudis86)
|
||||
target_link_libraries(hyprland_lib PUBLIC libudis86)
|
||||
endif()
|
||||
|
||||
# used by `make installheaders`, to ensure the headers are generated
|
||||
add_custom_target(generate-protocol-headers)
|
||||
set(PROTOCOL_SOURCES "")
|
||||
|
||||
function(protocolnew protoPath protoName external)
|
||||
if(external)
|
||||
|
|
@ -419,10 +435,15 @@ function(protocolnew protoPath protoName external)
|
|||
COMMAND hyprwayland-scanner ${path}/${protoName}.xml
|
||||
${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp
|
||||
target_sources(hyprland_lib PRIVATE protocols/${protoName}.cpp
|
||||
protocols/${protoName}.hpp)
|
||||
target_sources(generate-protocol-headers
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
|
||||
|
||||
list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp")
|
||||
set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
|
||||
list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp")
|
||||
set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
function(protocolWayland)
|
||||
add_custom_command(
|
||||
|
|
@ -432,12 +453,17 @@ function(protocolWayland)
|
|||
hyprwayland-scanner --wayland-enums
|
||||
${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
||||
target_sources(hyprland_lib PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
||||
target_sources(generate-protocol-headers
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
|
||||
|
||||
list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/wayland.hpp")
|
||||
set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
|
||||
list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/wayland.cpp")
|
||||
set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
|
||||
target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GL Threads::Threads)
|
||||
|
||||
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4)
|
||||
if(hyprland_protocols_dep_FOUND)
|
||||
|
|
@ -582,10 +608,37 @@ install(
|
|||
PATTERN "*.hpp"
|
||||
PATTERN "*.inc")
|
||||
|
||||
if(BUILD_TESTING OR BUILD_HYPRTESTER)
|
||||
message(STATUS "Building hyprtester")
|
||||
if(BUILD_TESTING OR WITH_TESTS)
|
||||
message(STATUS "Building tests")
|
||||
|
||||
# hyprtester
|
||||
add_subdirectory(hyprtester)
|
||||
|
||||
# GTest
|
||||
find_package(GTest CONFIG REQUIRED)
|
||||
include(GoogleTest)
|
||||
file(GLOB_RECURSE TESTFILES "tests/*.cpp")
|
||||
add_executable(hyprland_gtests ${TESTFILES})
|
||||
target_compile_options(hyprland_gtests PRIVATE --coverage)
|
||||
target_link_options(hyprland_gtests PRIVATE --coverage)
|
||||
target_include_directories(
|
||||
hyprland_gtests
|
||||
PUBLIC "./include"
|
||||
PRIVATE "./src" "./src/include" "./protocols" "${CMAKE_BINARY_DIR}")
|
||||
|
||||
target_link_libraries(hyprland_gtests hyprland_lib GTest::gtest_main)
|
||||
|
||||
gtest_discover_tests(hyprland_gtests)
|
||||
|
||||
# Enable coverage in main hyprland lib
|
||||
target_compile_options(hyprland_lib PRIVATE --coverage)
|
||||
target_link_options(hyprland_lib PRIVATE --coverage)
|
||||
target_link_libraries(hyprland_lib PUBLIC gcov)
|
||||
|
||||
# Enable coverage in hyprland exe
|
||||
target_compile_options(Hyprland PRIVATE --coverage)
|
||||
target_link_options(Hyprland PRIVATE --coverage)
|
||||
target_link_libraries(Hyprland gcov)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
|
@ -594,12 +647,8 @@ if(BUILD_TESTING)
|
|||
enable_testing()
|
||||
add_custom_target(tests)
|
||||
|
||||
add_test(
|
||||
NAME "Main Test"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/hyprtester
|
||||
COMMAND hyprtester)
|
||||
add_dependencies(tests hyprland_gtests)
|
||||
|
||||
add_dependencies(tests hyprtester)
|
||||
else()
|
||||
message(STATUS "Testing is disabled")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@
|
|||
# hyprland-packages
|
||||
hyprland
|
||||
hyprland-unwrapped
|
||||
hyprland-with-tests
|
||||
# hyprland-extras
|
||||
xdg-desktop-portal-hyprland
|
||||
;
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ static SDispatchResult scroll(std::string in) {
|
|||
}
|
||||
|
||||
static SDispatchResult keybind(std::string in) {
|
||||
CVarList data(in);
|
||||
CVarList2 data(std::move(in));
|
||||
// 0 = release, 1 = press
|
||||
bool press;
|
||||
// See src/devices/IKeyboard.hpp : eKeyboardModifiers for modifier bitmasks
|
||||
|
|
@ -234,9 +234,9 @@ static SDispatchResult keybind(std::string in) {
|
|||
// keycode
|
||||
uint32_t key;
|
||||
try {
|
||||
press = std::stoul(data[0]) == 1;
|
||||
modifier = std::stoul(data[1]);
|
||||
key = std::stoul(data[2]) - 8; // xkb offset
|
||||
press = std::stoul(std::string{data[0]}) == 1;
|
||||
modifier = std::stoul(std::string{data[1]});
|
||||
key = std::stoul(std::string{data[2]}) - 8; // xkb offset
|
||||
} catch (...) { return {.success = false, .error = "invalid input"}; }
|
||||
|
||||
uint32_t modifierMask = 0;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,17 @@ namespace Colors {
|
|||
constexpr const char* RESET = "\x1b[0m";
|
||||
};
|
||||
|
||||
#define EXPECT_MAX_DELTA(expr, desired, delta) \
|
||||
if (const auto RESULT = expr; std::abs(RESULT - (desired)) > delta) { \
|
||||
NLog::log("{}Failed: {}{}, expected max delta of {}, got delta {} ({} - {}). Source: {}@{}.", Colors::RED, Colors::RESET, #expr, delta, (RESULT - (desired)), RESULT, \
|
||||
desired, __FILE__, __LINE__); \
|
||||
ret = 1; \
|
||||
TESTS_FAILED++; \
|
||||
} else { \
|
||||
NLog::log("{}Passed: {}{}. Got {}", Colors::GREEN, Colors::RESET, #expr, (RESULT - (desired))); \
|
||||
TESTS_PASSED++; \
|
||||
}
|
||||
|
||||
#define EXPECT(expr, val) \
|
||||
if (const auto RESULT = expr; RESULT != (val)) { \
|
||||
NLog::log("{}Failed: {}{}, expected {}, got {}. Source: {}@{}.", Colors::RED, Colors::RESET, #expr, val, RESULT, __FILE__, __LINE__); \
|
||||
|
|
|
|||
|
|
@ -86,8 +86,7 @@ static void testBind() {
|
|||
// press keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 1,7,29"));
|
||||
// await flag
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT(checkFlag(), true);
|
||||
EXPECT(attemptCheckFlag(20, 50), true);
|
||||
// release keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
EXPECT(getFromSocket("/keyword unbind SUPER,Y"), "ok");
|
||||
|
|
@ -99,8 +98,7 @@ static void testBindKey() {
|
|||
// press keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 1,0,29"));
|
||||
// await flag
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT(checkFlag(), true);
|
||||
EXPECT(attemptCheckFlag(20, 50), true);
|
||||
// release keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
EXPECT(getFromSocket("/keyword unbind ,Y"), "ok");
|
||||
|
|
@ -116,7 +114,7 @@ static void testLongPress() {
|
|||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT(checkFlag(), false);
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), true);
|
||||
// release keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
|
|
@ -133,7 +131,7 @@ static void testKeyLongPress() {
|
|||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT(checkFlag(), false);
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), true);
|
||||
// release keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
|
|
@ -152,7 +150,7 @@ static void testLongPressRelease() {
|
|||
// release keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), false);
|
||||
EXPECT(getFromSocket("/keyword unbind SUPER,Y"), "ok");
|
||||
}
|
||||
|
|
@ -169,7 +167,7 @@ static void testLongPressOnlyKeyRelease() {
|
|||
// release key, keep modifier
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,7,29"));
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), false);
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
EXPECT(getFromSocket("/keyword unbind SUPER,Y"), "ok");
|
||||
|
|
@ -182,13 +180,13 @@ static void testRepeat() {
|
|||
// press keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 1,7,29"));
|
||||
// await flag
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), true);
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), true);
|
||||
// check that it continues repeating
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), true);
|
||||
// release keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
|
|
@ -205,10 +203,10 @@ static void testKeyRepeat() {
|
|||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT(checkFlag(), true);
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), true);
|
||||
// check that it continues repeating
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), true);
|
||||
// release keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
|
|
@ -227,10 +225,12 @@ static void testRepeatRelease() {
|
|||
// release keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
clearFlag();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), false);
|
||||
// check that it is not repeating
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), false);
|
||||
EXPECT(getFromSocket("/keyword unbind SUPER,Y"), "ok");
|
||||
}
|
||||
|
|
@ -242,15 +242,17 @@ static void testRepeatOnlyKeyRelease() {
|
|||
// press keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 1,7,29"));
|
||||
// await flag
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), true);
|
||||
// release key, keep modifier
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,7,29"));
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
clearFlag();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), false);
|
||||
// check that it is not repeating
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
EXPECT(checkFlag(), false);
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
EXPECT(getFromSocket("/keyword unbind SUPER,Y"), "ok");
|
||||
|
|
@ -315,9 +317,9 @@ static void testShortcutLongPress() {
|
|||
// press keybind
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 1,7,29"));
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(150));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,0,29"));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(150));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
const std::string output = readKittyOutput();
|
||||
int yCount = Tests::countOccurrences(output, "y");
|
||||
// sometimes 1, sometimes 2, not sure why
|
||||
|
|
@ -347,7 +349,7 @@ static void testShortcutLongPressKeyRelease() {
|
|||
// release key, keep modifier
|
||||
OK(getFromSocket("/dispatch plugin:test:keybind 0,7,29"));
|
||||
// await repeat delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(150));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
const std::string output = readKittyOutput();
|
||||
// disabled: doesn't work on CI
|
||||
// EXPECT_COUNT_STRING(output, "y", 1);
|
||||
|
|
@ -485,6 +487,8 @@ static void testSubmapUniversal() {
|
|||
static bool test() {
|
||||
NLog::log("{}Testing keybinds", Colors::GREEN);
|
||||
|
||||
clearFlag();
|
||||
|
||||
testBind();
|
||||
testBindKey();
|
||||
testLongPress();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <thread>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
#include <hyprutils/memory/WeakPtr.hpp>
|
||||
#include <hyprutils/string/VarList2.hpp>
|
||||
|
||||
#include "../../shared.hpp"
|
||||
#include "../../hyprctlCompat.hpp"
|
||||
|
|
@ -364,22 +365,40 @@ static bool test() {
|
|||
|
||||
NLog::log("{}Testing window split ratios", Colors::YELLOW);
|
||||
{
|
||||
const double RATIO = 1.25;
|
||||
const double PERCENT = RATIO / 2.0 * 100.0;
|
||||
const int GAPSIN = 5;
|
||||
const int GAPSOUT = 20;
|
||||
const int BORDERS = 2 * 2;
|
||||
const int WTRIM = BORDERS + GAPSIN + GAPSOUT;
|
||||
const int HEIGHT = 1080 - (BORDERS + (GAPSOUT * 2));
|
||||
const int WIDTH1 = std::round(1920.0 / 2.0 * (2 - RATIO)) - WTRIM;
|
||||
const int WIDTH2 = std::round(1920.0 / 2.0 * RATIO) - WTRIM;
|
||||
const double INITIAL_RATIO = 1.25;
|
||||
const int GAPSIN = 5;
|
||||
const int GAPSOUT = 20;
|
||||
const int BORDERSIZE = 2;
|
||||
const int BORDERS = BORDERSIZE * 2;
|
||||
const int MONITOR_W = 1920;
|
||||
const int MONITOR_H = 1080;
|
||||
|
||||
const float totalAvailableHeight = MONITOR_H - (GAPSOUT * 2);
|
||||
const int HEIGHT = std::floor(totalAvailableHeight) - BORDERS;
|
||||
const float availableWidthForSplit = MONITOR_W - (GAPSOUT * 2) - GAPSIN;
|
||||
|
||||
auto calculateFinalWidth = [&](double boxWidth, bool isLeftWindow) {
|
||||
double gapLeft = isLeftWindow ? GAPSOUT : GAPSIN;
|
||||
double gapRight = isLeftWindow ? GAPSIN : GAPSOUT;
|
||||
return std::floor(boxWidth - gapLeft - gapRight - BORDERS);
|
||||
};
|
||||
|
||||
double geomBoxWidthA_R1 = (availableWidthForSplit * INITIAL_RATIO / 2.0) + GAPSOUT + (GAPSIN / 2.0);
|
||||
double geomBoxWidthB_R1 = MONITOR_W - geomBoxWidthA_R1;
|
||||
const int WIDTH1 = calculateFinalWidth(geomBoxWidthB_R1, false);
|
||||
|
||||
const double INVERTED_RATIO = 0.75;
|
||||
double geomBoxWidthA_R2 = (availableWidthForSplit * INVERTED_RATIO / 2.0) + GAPSOUT + (GAPSIN / 2.0);
|
||||
double geomBoxWidthB_R2 = MONITOR_W - geomBoxWidthA_R2;
|
||||
const int WIDTH2 = calculateFinalWidth(geomBoxWidthB_R2, false);
|
||||
const int WIDTH_A_FINAL = calculateFinalWidth(geomBoxWidthA_R2, true);
|
||||
|
||||
OK(getFromSocket("/keyword dwindle:default_split_ratio 1.25"));
|
||||
|
||||
if (!spawnKitty("kitty_B"))
|
||||
return false;
|
||||
|
||||
NLog::log("{}Expecting kitty_B to take up roughly {}% of screen width", Colors::YELLOW, 100 - PERCENT);
|
||||
NLog::log("{}Expecting kitty_B size: {},{}", Colors::YELLOW, WIDTH1, HEIGHT);
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH1, HEIGHT));
|
||||
|
||||
OK(getFromSocket("/dispatch killwindow activewindow"));
|
||||
|
|
@ -391,12 +410,38 @@ static bool test() {
|
|||
if (!spawnKitty("kitty_B"))
|
||||
return false;
|
||||
|
||||
NLog::log("{}Expecting kitty_B to take up roughly {}% of screen width", Colors::YELLOW, PERCENT);
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH2, HEIGHT));
|
||||
try {
|
||||
NLog::log("{}Expecting kitty_B size: {},{}", Colors::YELLOW, WIDTH2, HEIGHT);
|
||||
|
||||
OK(getFromSocket("/dispatch focuswindow class:kitty_A"));
|
||||
NLog::log("{}Expecting kitty_A to have the same width as the previous kitty_B", Colors::YELLOW);
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), std::format("size: {},{}", WIDTH1, HEIGHT));
|
||||
{
|
||||
auto data = getFromSocket("/activewindow");
|
||||
data = data.substr(data.find("size:") + 5);
|
||||
data = data.substr(0, data.find('\n'));
|
||||
|
||||
Hyprutils::String::CVarList2 sizes(std::move(data), 0, ',');
|
||||
|
||||
EXPECT_MAX_DELTA(std::stoi(std::string{sizes[0]}), WIDTH2, 2);
|
||||
EXPECT_MAX_DELTA(std::stoi(std::string{sizes[1]}), HEIGHT, 2);
|
||||
}
|
||||
|
||||
OK(getFromSocket("/dispatch focuswindow class:kitty_A"));
|
||||
NLog::log("{}Expecting kitty_A size: {},{}", Colors::YELLOW, WIDTH_A_FINAL, HEIGHT);
|
||||
|
||||
{
|
||||
auto data = getFromSocket("/activewindow");
|
||||
data = data.substr(data.find("size:") + 5);
|
||||
data = data.substr(0, data.find('\n'));
|
||||
|
||||
Hyprutils::String::CVarList2 sizes(std::move(data), 0, ',');
|
||||
|
||||
EXPECT_MAX_DELTA(std::stoi(std::string{sizes[0]}), WIDTH_A_FINAL, 2);
|
||||
EXPECT_MAX_DELTA(std::stoi(std::string{sizes[1]}), HEIGHT, 2);
|
||||
}
|
||||
|
||||
} catch (...) {
|
||||
NLog::log("{}Exception thrown", Colors::RED);
|
||||
EXPECT(false, true);
|
||||
}
|
||||
|
||||
OK(getFromSocket("/keyword dwindle:default_split_ratio 1"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <chrono>
|
||||
#include <hyprutils/os/Process.hpp>
|
||||
#include <hyprutils/memory/WeakPtr.hpp>
|
||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||
#include <csignal>
|
||||
#include <cerrno>
|
||||
#include "../shared.hpp"
|
||||
|
|
@ -14,10 +15,99 @@ static int ret = 0;
|
|||
|
||||
using namespace Hyprutils::OS;
|
||||
using namespace Hyprutils::Memory;
|
||||
using namespace Hyprutils::Utils;
|
||||
|
||||
#define UP CUniquePointer
|
||||
#define SP CSharedPointer
|
||||
|
||||
static bool testAsymmetricGaps() {
|
||||
NLog::log("{}Testing asymmetric gap splits", Colors::YELLOW);
|
||||
{
|
||||
|
||||
CScopeGuard guard = {[&]() {
|
||||
NLog::log("{}Cleaning up asymmetric gap test", Colors::YELLOW);
|
||||
Tests::killAllWindows();
|
||||
OK(getFromSocket("/reload"));
|
||||
}};
|
||||
|
||||
OK(getFromSocket("/dispatch workspace name:gap_split_test"));
|
||||
OK(getFromSocket("r/keyword general:gaps_in 0"));
|
||||
OK(getFromSocket("r/keyword general:border_size 0"));
|
||||
OK(getFromSocket("r/keyword dwindle:split_width_multiplier 1.0"));
|
||||
OK(getFromSocket("r/keyword workspace name:gap_split_test,gapsout:0 1000 0 0"));
|
||||
|
||||
NLog::log("{}Testing default split (force_split = 0)", Colors::YELLOW);
|
||||
OK(getFromSocket("r/keyword dwindle:force_split 0"));
|
||||
|
||||
if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
|
||||
return false;
|
||||
|
||||
NLog::log("{}Expecting vertical split (B below A)", Colors::YELLOW);
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
|
||||
|
||||
Tests::killAllWindows();
|
||||
EXPECT(Tests::windowCount(), 0);
|
||||
|
||||
NLog::log("{}Testing force_split = 1", Colors::YELLOW);
|
||||
OK(getFromSocket("r/keyword dwindle:force_split 1"));
|
||||
|
||||
if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
|
||||
return false;
|
||||
|
||||
NLog::log("{}Expecting vertical split (B above A)", Colors::YELLOW);
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
|
||||
|
||||
NLog::log("{}Expecting horizontal split (C left of B)", Colors::YELLOW);
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
|
||||
|
||||
if (!Tests::spawnKitty("gaps_kitty_C"))
|
||||
return false;
|
||||
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_C"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 460,0");
|
||||
|
||||
Tests::killAllWindows();
|
||||
EXPECT(Tests::windowCount(), 0);
|
||||
|
||||
NLog::log("{}Testing force_split = 2", Colors::YELLOW);
|
||||
OK(getFromSocket("r/keyword dwindle:force_split 2"));
|
||||
|
||||
if (!Tests::spawnKitty("gaps_kitty_A") || !Tests::spawnKitty("gaps_kitty_B"))
|
||||
return false;
|
||||
|
||||
NLog::log("{}Expecting vertical split (B below A)", Colors::YELLOW);
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_B"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,540");
|
||||
|
||||
NLog::log("{}Expecting horizontal split (C right of A)", Colors::YELLOW);
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
|
||||
|
||||
if (!Tests::spawnKitty("gaps_kitty_C"))
|
||||
return false;
|
||||
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_A"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 0,0");
|
||||
OK(getFromSocket("/dispatch focuswindow class:gaps_kitty_C"));
|
||||
EXPECT_CONTAINS(getFromSocket("/activewindow"), "at: 460,0");
|
||||
}
|
||||
|
||||
// kill all
|
||||
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||
Tests::killAllWindows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test() {
|
||||
NLog::log("{}Testing workspaces", Colors::GREEN);
|
||||
|
||||
|
|
@ -359,6 +449,8 @@ static bool test() {
|
|||
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||
Tests::killAllWindows();
|
||||
|
||||
testAsymmetricGaps();
|
||||
|
||||
NLog::log("{}Expecting 0 windows", Colors::YELLOW);
|
||||
EXPECT(Tests::windowCount(), 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
epoll-shim,
|
||||
git,
|
||||
glaze,
|
||||
gtest,
|
||||
hyprcursor,
|
||||
hyprgraphics,
|
||||
hyprland-protocols,
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
xorg,
|
||||
xwayland,
|
||||
debug ? false,
|
||||
withTests ? false,
|
||||
enableXWayland ? true,
|
||||
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
|
||||
wrapRuntimeDeps ? true,
|
||||
|
|
@ -75,7 +77,7 @@ in
|
|||
assert assertMsg (!withHyprtester) "The option `withHyprtester` has been removed. Hyprtester is always built now.";
|
||||
customStdenv.mkDerivation (finalAttrs: {
|
||||
pname = "hyprland${optionalString debug "-debug"}";
|
||||
inherit version;
|
||||
inherit version withTests;
|
||||
|
||||
src = fs.toSource {
|
||||
root = ../.;
|
||||
|
|
@ -88,7 +90,6 @@ in
|
|||
../assets/install
|
||||
../hyprctl
|
||||
../hyprland.pc.in
|
||||
../hyprtester
|
||||
../LICENSE
|
||||
../protocols
|
||||
../src
|
||||
|
|
@ -98,6 +99,7 @@ in
|
|||
(fs.fileFilter (file: file.hasExt "conf" || file.hasExt "desktop") ../example)
|
||||
(fs.fileFilter (file: file.hasExt "sh") ../scripts)
|
||||
(fs.fileFilter (file: file.name == "CMakeLists.txt") ../.)
|
||||
(optional withTests [../tests ../hyprtester])
|
||||
]));
|
||||
};
|
||||
|
||||
|
|
@ -141,6 +143,7 @@ in
|
|||
cairo
|
||||
git
|
||||
glaze
|
||||
gtest
|
||||
hyprcursor
|
||||
hyprgraphics
|
||||
hyprland-protocols
|
||||
|
|
@ -195,7 +198,7 @@ in
|
|||
"NO_UWSM" = true;
|
||||
"NO_HYPRPM" = true;
|
||||
"TRACY_ENABLE" = false;
|
||||
"BUILD_HYPRTESTER" = true;
|
||||
"WITH_TESTS" = withTests;
|
||||
};
|
||||
|
||||
preConfigure = ''
|
||||
|
|
@ -215,8 +218,11 @@ in
|
|||
]}
|
||||
''}
|
||||
|
||||
install hyprtester/pointer-warp -t $out/bin
|
||||
install hyprtester/pointer-scroll -t $out/bin
|
||||
${optionalString withTests ''
|
||||
install hyprtester/pointer-warp -t $out/bin
|
||||
install hyprtester/pointer-scroll -t $out/bin
|
||||
install hyprland_gtests -t $out/bin
|
||||
''}
|
||||
'';
|
||||
|
||||
passthru.providedSessions = ["hyprland"];
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ in {
|
|||
};
|
||||
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
|
||||
|
||||
hyprland-with-tests = final.hyprland.override {withTests = true;};
|
||||
|
||||
hyprland-with-hyprtester =
|
||||
builtins.trace ''
|
||||
hyprland-with-hyprtester was removed. Please use the hyprland package.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
inputs: pkgs: let
|
||||
flake = inputs.self.packages.${pkgs.stdenv.hostPlatform.system};
|
||||
hyprland = flake.hyprland;
|
||||
hyprland = flake.hyprland-with-tests;
|
||||
in {
|
||||
tests = pkgs.testers.runNixOSTest {
|
||||
name = "hyprland-tests";
|
||||
|
|
@ -68,6 +68,12 @@ in {
|
|||
# Wait for tty to be up
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
|
||||
# Run gtests
|
||||
print("Running gtests")
|
||||
exit_status, _out = machine.execute("su - alice -c 'hyprland_gtests 2>&1 | tee /tmp/gtestslog; exit ''${PIPESTATUS[0]}'")
|
||||
machine.execute(f'echo {exit_status} > /tmp/exit_status_gtests')
|
||||
|
||||
# Run hyprtester testing framework/suite
|
||||
print("Running hyprtester")
|
||||
exit_status, _out = machine.execute("su - alice -c 'hyprtester -b ${hyprland}/bin/Hyprland -c /etc/test.conf -p ${hyprland}/lib/hyprtestplugin.so 2>&1 | tee /tmp/testerlog; exit ''${PIPESTATUS[0]}'")
|
||||
|
|
@ -76,6 +82,7 @@ in {
|
|||
# Copy logs to host
|
||||
machine.execute('cp "$(find /tmp/hypr -name *.log | head -1)" /tmp/hyprlog')
|
||||
machine.execute(f'echo {exit_status} > /tmp/exit_status')
|
||||
machine.copy_from_vm("/tmp/gtestslog")
|
||||
machine.copy_from_vm("/tmp/testerlog")
|
||||
machine.copy_from_vm("/tmp/hyprlog")
|
||||
machine.copy_from_vm("/tmp/exit_status")
|
||||
|
|
|
|||
|
|
@ -1607,10 +1607,13 @@ bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) {
|
|||
bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR pMonitor) {
|
||||
const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector(point);
|
||||
|
||||
const auto XY1 = PMONITOR->m_position + PMONITOR->m_reservedTopLeft;
|
||||
const auto XY2 = PMONITOR->m_position + PMONITOR->m_size - PMONITOR->m_reservedBottomRight;
|
||||
auto box = PMONITOR->logicalBox();
|
||||
if (VECNOTINRECT(point, box.x - 1, box.y - 1, box.w + 2, box.h + 2))
|
||||
return false;
|
||||
|
||||
return VECNOTINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y);
|
||||
PMONITOR->m_reservedArea.applyip(box);
|
||||
|
||||
return VECNOTINRECT(point, box.x, box.y, box.x, box.y);
|
||||
}
|
||||
|
||||
CBox CCompositor::calculateX11WorkArea() {
|
||||
|
|
@ -1620,11 +1623,7 @@ CBox CCompositor::calculateX11WorkArea() {
|
|||
|
||||
for (const auto& monitor : m_monitors) {
|
||||
// we ignore monitor->m_position on purpose
|
||||
auto x = monitor->m_reservedTopLeft.x;
|
||||
auto y = monitor->m_reservedTopLeft.y;
|
||||
auto w = monitor->m_size.x - monitor->m_reservedBottomRight.x - x;
|
||||
auto h = monitor->m_size.y - monitor->m_reservedBottomRight.y - y;
|
||||
CBox box = {x, y, w, h};
|
||||
CBox box = monitor->logicalBoxMinusReserved().translate(-monitor->m_position);
|
||||
if ((*PXWLFORCESCALEZERO))
|
||||
box.scale(monitor->m_scale);
|
||||
|
||||
|
|
|
|||
|
|
@ -1095,7 +1095,6 @@ std::optional<std::string> CConfigManager::resetHLConfig() {
|
|||
g_pAnimationManager->addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0));
|
||||
g_pTrackpadGestures->clearGestures();
|
||||
|
||||
m_mAdditionalReservedAreas.clear();
|
||||
m_workspaceRules.clear();
|
||||
setDefaultAnimationVars(); // reset anims
|
||||
m_declaredPlugins.clear();
|
||||
|
|
@ -1139,7 +1138,8 @@ std::optional<std::string> CConfigManager::handleMonitorv2(const std::string& ou
|
|||
if (VAL && VAL->m_bSetByUser) {
|
||||
const auto ARGS = CVarList(std::any_cast<Hyprlang::STRING>(VAL->getValue()));
|
||||
try {
|
||||
parser.setReserved({.top = std::stoi(ARGS[0]), .bottom = std::stoi(ARGS[1]), .left = std::stoi(ARGS[2]), .right = std::stoi(ARGS[3])});
|
||||
// top, right, bottom, left
|
||||
parser.setReserved({std::stoi(ARGS[0]), std::stoi(ARGS[3]), std::stoi(ARGS[1]), std::stoi(ARGS[2])});
|
||||
} catch (...) { return "parse error: invalid reserved area"; }
|
||||
}
|
||||
VAL = m_config->getSpecialConfigValuePtr("monitorv2", "mirror", output.c_str());
|
||||
|
|
@ -2193,8 +2193,8 @@ void CMonitorRuleParser::setMirror(const std::string& value) {
|
|||
m_rule.mirrorOf = value;
|
||||
}
|
||||
|
||||
bool CMonitorRuleParser::setReserved(const SMonitorAdditionalReservedArea& value) {
|
||||
g_pConfigManager->m_mAdditionalReservedAreas[name()] = value;
|
||||
bool CMonitorRuleParser::setReserved(const Desktop::CReservedArea& value) {
|
||||
m_rule.reservedArea = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2223,13 +2223,22 @@ std::optional<std::string> CConfigManager::handleMonitor(const std::string& comm
|
|||
|
||||
return {};
|
||||
} else if (ARGS[1] == "addreserved") {
|
||||
std::optional<Desktop::CReservedArea> area;
|
||||
try {
|
||||
parser.setReserved({.top = std::stoi(std::string(ARGS[2])),
|
||||
.bottom = std::stoi(std::string(ARGS[3])),
|
||||
.left = std::stoi(std::string(ARGS[4])),
|
||||
.right = std::stoi(std::string(ARGS[5]))});
|
||||
// top, right, bottom, left
|
||||
area = {std::stoi(std::string{ARGS[2]}), std::stoi(std::string{ARGS[5]}), std::stoi(std::string{ARGS[3]}), std::stoi(std::string{ARGS[4]})};
|
||||
} catch (...) { return "parse error: invalid reserved area"; }
|
||||
return {};
|
||||
|
||||
if (!area.has_value())
|
||||
return "parse error: bad addreserved";
|
||||
|
||||
auto rule = std::ranges::find_if(m_monitorRules, [n = ARGS[0]](const auto& other) { return other.name == n; });
|
||||
if (rule != m_monitorRules.end()) {
|
||||
rule->reservedArea = area.value();
|
||||
return {};
|
||||
}
|
||||
|
||||
// fall
|
||||
} else {
|
||||
Debug::log(ERR, "ConfigManager parseMonitor, curitem bogus???");
|
||||
return "parse error: curitem bogus";
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "../SharedDefs.hpp"
|
||||
#include "../helpers/Color.hpp"
|
||||
#include "../desktop/DesktopTypes.hpp"
|
||||
#include "../desktop/reserved/ReservedArea.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../managers/XWaylandManager.hpp"
|
||||
#include "../managers/KeybindManager.hpp"
|
||||
|
|
@ -48,13 +49,6 @@ struct SWorkspaceRule {
|
|||
std::map<std::string, std::string> layoutopts;
|
||||
};
|
||||
|
||||
struct SMonitorAdditionalReservedArea {
|
||||
int top = 0;
|
||||
int bottom = 0;
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
};
|
||||
|
||||
struct SPluginKeyword {
|
||||
HANDLE handle = nullptr;
|
||||
std::string name = "";
|
||||
|
|
@ -185,7 +179,7 @@ class CMonitorRuleParser {
|
|||
|
||||
void setDisabled();
|
||||
void setMirror(const std::string& value);
|
||||
bool setReserved(const SMonitorAdditionalReservedArea& value);
|
||||
bool setReserved(const Desktop::CReservedArea& value);
|
||||
|
||||
private:
|
||||
SMonitorRule m_rule;
|
||||
|
|
@ -196,36 +190,34 @@ class CConfigManager {
|
|||
public:
|
||||
CConfigManager();
|
||||
|
||||
void init();
|
||||
void reload();
|
||||
std::string verify();
|
||||
void init();
|
||||
void reload();
|
||||
std::string verify();
|
||||
|
||||
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
bool deviceConfigExplicitlySet(const std::string&, const std::string&);
|
||||
bool deviceConfigExists(const std::string&);
|
||||
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
|
||||
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
|
||||
bool deviceConfigExplicitlySet(const std::string&, const std::string&);
|
||||
bool deviceConfigExists(const std::string&);
|
||||
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
|
||||
|
||||
void* const* getConfigValuePtr(const std::string&);
|
||||
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
|
||||
std::string getMainConfigPath();
|
||||
std::string getConfigString();
|
||||
void* const* getConfigValuePtr(const std::string&);
|
||||
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
|
||||
std::string getMainConfigPath();
|
||||
std::string getConfigString();
|
||||
|
||||
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
|
||||
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
|
||||
std::string getDefaultWorkspaceFor(const std::string&);
|
||||
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
|
||||
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
|
||||
std::string getDefaultWorkspaceFor(const std::string&);
|
||||
|
||||
PHLMONITOR getBoundMonitorForWS(const std::string&);
|
||||
std::string getBoundMonitorStringForWS(const std::string&);
|
||||
const std::vector<SWorkspaceRule>& getAllWorkspaceRules();
|
||||
PHLMONITOR getBoundMonitorForWS(const std::string&);
|
||||
std::string getBoundMonitorStringForWS(const std::string&);
|
||||
const std::vector<SWorkspaceRule>& getAllWorkspaceRules();
|
||||
|
||||
void ensurePersistentWorkspacesPresent();
|
||||
void ensurePersistentWorkspacesPresent();
|
||||
|
||||
const std::vector<SConfigOptionDescription>& getAllDescriptions();
|
||||
|
||||
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
|
||||
const std::vector<SConfigOptionDescription>& getAllDescriptions();
|
||||
|
||||
const std::unordered_map<std::string, SP<Hyprutils::Animation::SAnimationPropertyConfig>>& getAnimationConfig();
|
||||
|
||||
|
|
|
|||
|
|
@ -255,8 +255,8 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
|
|||
escapeJSONStrings(m->m_output->serial), sc<int>(m->m_pixelSize.x), sc<int>(m->m_pixelSize.y), sc<int>(m->m_output->physicalSize.x),
|
||||
sc<int>(m->m_output->physicalSize.y), m->m_refreshRate, sc<int>(m->m_position.x), sc<int>(m->m_position.y), m->activeWorkspaceID(),
|
||||
(!m->m_activeWorkspace ? "" : escapeJSONStrings(m->m_activeWorkspace->m_name)), m->activeSpecialWorkspaceID(),
|
||||
escapeJSONStrings(m->m_activeSpecialWorkspace ? m->m_activeSpecialWorkspace->m_name : ""), sc<int>(m->m_reservedTopLeft.x), sc<int>(m->m_reservedTopLeft.y),
|
||||
sc<int>(m->m_reservedBottomRight.x), sc<int>(m->m_reservedBottomRight.y), m->m_scale, sc<int>(m->m_transform),
|
||||
escapeJSONStrings(m->m_activeSpecialWorkspace ? m->m_activeSpecialWorkspace->m_name : ""), sc<int>(m->m_reservedArea.left()), sc<int>(m->m_reservedArea.top()),
|
||||
sc<int>(m->m_reservedArea.right()), sc<int>(m->m_reservedArea.bottom()), m->m_scale, sc<int>(m->m_transform),
|
||||
(m == Desktop::focusState()->monitor() ? "true" : "false"), (m->m_dpmsStatus ? "true" : "false"), (m->m_output->state->state().adaptiveSync ? "true" : "false"),
|
||||
rc<uint64_t>(m->m_solitaryClient.get()), getSolitaryBlockedReason(m, format), (m->m_tearingState.activelyTearing ? "true" : "false"),
|
||||
getTearingBlockedReason(m, format), rc<uint64_t>(m->m_lastScanout.get()), getDSBlockedReason(m, format), (m->m_enabled ? "false" : "true"),
|
||||
|
|
@ -274,7 +274,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
|
|||
m->m_name, m->m_id, sc<int>(m->m_pixelSize.x), sc<int>(m->m_pixelSize.y), m->m_refreshRate, sc<int>(m->m_position.x), sc<int>(m->m_position.y), m->m_shortDescription,
|
||||
m->m_output->make, m->m_output->model, sc<int>(m->m_output->physicalSize.x), sc<int>(m->m_output->physicalSize.y), m->m_output->serial, m->activeWorkspaceID(),
|
||||
(!m->m_activeWorkspace ? "" : m->m_activeWorkspace->m_name), m->activeSpecialWorkspaceID(), (m->m_activeSpecialWorkspace ? m->m_activeSpecialWorkspace->m_name : ""),
|
||||
sc<int>(m->m_reservedTopLeft.x), sc<int>(m->m_reservedTopLeft.y), sc<int>(m->m_reservedBottomRight.x), sc<int>(m->m_reservedBottomRight.y), m->m_scale,
|
||||
sc<int>(m->m_reservedArea.left()), sc<int>(m->m_reservedArea.top()), sc<int>(m->m_reservedArea.right()), sc<int>(m->m_reservedArea.bottom()), m->m_scale,
|
||||
sc<int>(m->m_transform), (m == Desktop::focusState()->monitor() ? "yes" : "no"), sc<int>(m->m_dpmsStatus), m->m_output->state->state().adaptiveSync,
|
||||
rc<uint64_t>(m->m_solitaryClient.get()), getSolitaryBlockedReason(m, format), m->m_tearingState.activelyTearing, getTearingBlockedReason(m, format),
|
||||
rc<uint64_t>(m->m_lastScanout.get()), getDSBlockedReason(m, format), !m->m_enabled, formatToString(m->m_output->state->state().drmFormat),
|
||||
|
|
|
|||
|
|
@ -229,19 +229,19 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
|||
return CBox{sc<int>(POS.x), sc<int>(POS.y), sc<int>(SIZE.x), sc<int>(SIZE.y)};
|
||||
}
|
||||
|
||||
if (DELTALESSTHAN(POS.y - PMONITOR->m_position.y, PMONITOR->m_reservedTopLeft.y, 1)) {
|
||||
if (DELTALESSTHAN(POS.y - PMONITOR->m_position.y, PMONITOR->m_reservedArea.top(), 1)) {
|
||||
POS.y = PMONITOR->m_position.y;
|
||||
SIZE.y += PMONITOR->m_reservedTopLeft.y;
|
||||
SIZE.y += PMONITOR->m_reservedArea.top();
|
||||
}
|
||||
if (DELTALESSTHAN(POS.x - PMONITOR->m_position.x, PMONITOR->m_reservedTopLeft.x, 1)) {
|
||||
if (DELTALESSTHAN(POS.x - PMONITOR->m_position.x, PMONITOR->m_reservedArea.left(), 1)) {
|
||||
POS.x = PMONITOR->m_position.x;
|
||||
SIZE.x += PMONITOR->m_reservedTopLeft.x;
|
||||
SIZE.x += PMONITOR->m_reservedArea.left();
|
||||
}
|
||||
if (DELTALESSTHAN(POS.x + SIZE.x - PMONITOR->m_position.x, PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x, 1)) {
|
||||
SIZE.x += PMONITOR->m_reservedBottomRight.x;
|
||||
if (DELTALESSTHAN(POS.x + SIZE.x - PMONITOR->m_position.x, PMONITOR->m_size.x - PMONITOR->m_reservedArea.right(), 1)) {
|
||||
SIZE.x += PMONITOR->m_reservedArea.right();
|
||||
}
|
||||
if (DELTALESSTHAN(POS.y + SIZE.y - PMONITOR->m_position.y, PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y, 1)) {
|
||||
SIZE.y += PMONITOR->m_reservedBottomRight.y;
|
||||
if (DELTALESSTHAN(POS.y + SIZE.y - PMONITOR->m_position.y, PMONITOR->m_size.y - PMONITOR->m_reservedArea.bottom(), 1)) {
|
||||
SIZE.y += PMONITOR->m_reservedArea.bottom();
|
||||
}
|
||||
|
||||
return CBox{sc<int>(POS.x), sc<int>(POS.y), sc<int>(SIZE.x), sc<int>(SIZE.y)};
|
||||
|
|
|
|||
89
src/desktop/reserved/ReservedArea.cpp
Normal file
89
src/desktop/reserved/ReservedArea.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#include "ReservedArea.hpp"
|
||||
#include "../../macros.hpp"
|
||||
|
||||
using namespace Desktop;
|
||||
|
||||
// fuck me. Writing this at 11pm, and I have an in-class test tomorrow.
|
||||
// I am failing that bitch
|
||||
|
||||
CReservedArea::CReservedArea(const Vector2D& tl, const Vector2D& br) : m_initialTopLeft(tl), m_initialBottomRight(br) {
|
||||
calculate();
|
||||
}
|
||||
|
||||
CReservedArea::CReservedArea(double top, double right, double bottom, double left) : m_initialTopLeft(left, top), m_initialBottomRight(right, bottom) {
|
||||
calculate();
|
||||
}
|
||||
|
||||
CReservedArea::CReservedArea(const CBox& parent, const CBox& child) {
|
||||
ASSERT(!parent.empty() && !child.empty());
|
||||
|
||||
ASSERT(parent.containsPoint(child.pos() + Vector2D{0.0001, 0.0001}));
|
||||
ASSERT(parent.containsPoint(child.pos() + child.size() - Vector2D{0.0001, 0.0001}));
|
||||
|
||||
m_initialTopLeft = child.pos() - parent.pos();
|
||||
m_initialBottomRight = (parent.pos() + parent.size()) - (child.pos() + child.size());
|
||||
|
||||
calculate();
|
||||
}
|
||||
|
||||
void CReservedArea::calculate() {
|
||||
m_bottomRight = m_initialBottomRight;
|
||||
m_topLeft = m_initialTopLeft;
|
||||
|
||||
for (const auto& e : m_dynamicReserved) {
|
||||
m_bottomRight += e.bottomRight;
|
||||
m_topLeft += e.topLeft;
|
||||
}
|
||||
}
|
||||
|
||||
CBox CReservedArea::apply(const CBox& other) const {
|
||||
auto c = other.copy();
|
||||
c.x += m_topLeft.x;
|
||||
c.y += m_topLeft.y;
|
||||
c.w -= m_topLeft.x + m_bottomRight.x;
|
||||
c.h -= m_topLeft.y + m_bottomRight.y;
|
||||
return c;
|
||||
}
|
||||
|
||||
void CReservedArea::applyip(CBox& other) const {
|
||||
other.x += m_topLeft.x;
|
||||
other.y += m_topLeft.y;
|
||||
other.w -= m_topLeft.x + m_bottomRight.x;
|
||||
other.h -= m_topLeft.y + m_bottomRight.y;
|
||||
}
|
||||
|
||||
bool CReservedArea::operator==(const CReservedArea& other) const {
|
||||
return other.m_bottomRight == m_bottomRight && other.m_topLeft == m_topLeft;
|
||||
}
|
||||
|
||||
double CReservedArea::left() const {
|
||||
return m_topLeft.x;
|
||||
}
|
||||
|
||||
double CReservedArea::right() const {
|
||||
return m_bottomRight.x;
|
||||
}
|
||||
|
||||
double CReservedArea::top() const {
|
||||
return m_topLeft.y;
|
||||
}
|
||||
|
||||
double CReservedArea::bottom() const {
|
||||
return m_bottomRight.y;
|
||||
}
|
||||
|
||||
void CReservedArea::resetType(eReservedDynamicType t) {
|
||||
m_dynamicReserved[t] = {};
|
||||
calculate();
|
||||
}
|
||||
|
||||
void CReservedArea::addType(eReservedDynamicType t, const Vector2D& topLeft, const Vector2D& bottomRight) {
|
||||
auto& ref = m_dynamicReserved[t];
|
||||
ref.topLeft += topLeft;
|
||||
ref.bottomRight += bottomRight;
|
||||
calculate();
|
||||
}
|
||||
|
||||
void CReservedArea::addType(eReservedDynamicType t, const CReservedArea& area) {
|
||||
addType(t, {area.left(), area.top()}, {area.right(), area.bottom()});
|
||||
}
|
||||
48
src/desktop/reserved/ReservedArea.hpp
Normal file
48
src/desktop/reserved/ReservedArea.hpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../helpers/math/Math.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace Desktop {
|
||||
enum eReservedDynamicType : uint8_t {
|
||||
RESERVED_DYNAMIC_TYPE_LS = 0,
|
||||
RESERVED_DYNAMIC_TYPE_ERROR_BAR,
|
||||
|
||||
RESERVED_DYNAMIC_TYPE_END,
|
||||
};
|
||||
|
||||
class CReservedArea {
|
||||
public:
|
||||
CReservedArea() = default;
|
||||
CReservedArea(const Vector2D& tl, const Vector2D& br);
|
||||
CReservedArea(double top, double right, double bottom, double left);
|
||||
CReservedArea(const CBox& parent, const CBox& child);
|
||||
~CReservedArea() = default;
|
||||
|
||||
CBox apply(const CBox& other) const;
|
||||
void applyip(CBox& other) const;
|
||||
|
||||
void resetType(eReservedDynamicType);
|
||||
void addType(eReservedDynamicType, const Vector2D& topLeft, const Vector2D& bottomRight);
|
||||
void addType(eReservedDynamicType, const CReservedArea& area);
|
||||
|
||||
double left() const;
|
||||
double right() const;
|
||||
double top() const;
|
||||
double bottom() const;
|
||||
|
||||
bool operator==(const CReservedArea& other) const;
|
||||
|
||||
private:
|
||||
void calculate();
|
||||
|
||||
Vector2D m_topLeft, m_bottomRight;
|
||||
Vector2D m_initialTopLeft, m_initialBottomRight;
|
||||
|
||||
struct SDynamicData {
|
||||
Vector2D topLeft, bottomRight;
|
||||
};
|
||||
|
||||
std::array<SDynamicData, RESERVED_DYNAMIC_TYPE_END> m_dynamicReserved;
|
||||
};
|
||||
};
|
||||
|
|
@ -396,8 +396,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
}
|
||||
|
||||
if (PWINDOW->m_ruleApplicator->static_.center) {
|
||||
auto RESERVEDOFFSET = (PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight) / 2.f;
|
||||
*PWINDOW->m_realPosition = PMONITOR->middle() - PWINDOW->m_realSize->goal() / 2.f + RESERVEDOFFSET;
|
||||
const auto WORKAREA = PMONITOR->logicalBoxMinusReserved();
|
||||
*PWINDOW->m_realPosition = WORKAREA.middle() - PWINDOW->m_realSize->goal() / 2.f;
|
||||
}
|
||||
|
||||
// set the pseudo size to the GOAL of our current size
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
|
|||
&& m_transform == RULE->transform && RULE->enable10bit == m_enabled10bit && RULE->cmType == m_cmType && RULE->sdrSaturation == m_sdrSaturation &&
|
||||
RULE->sdrBrightness == m_sdrBrightness && RULE->sdrMinLuminance == m_minLuminance && RULE->sdrMaxLuminance == m_maxLuminance &&
|
||||
RULE->supportsWideColor == m_supportsWideColor && RULE->supportsHDR == m_supportsHDR && RULE->minLuminance == m_minLuminance && RULE->maxLuminance == m_maxLuminance &&
|
||||
RULE->maxAvgLuminance == m_maxAvgLuminance && !std::memcmp(&m_customDrmMode, &RULE->drmMode, sizeof(m_customDrmMode))) {
|
||||
RULE->maxAvgLuminance == m_maxAvgLuminance && !std::memcmp(&m_customDrmMode, &RULE->drmMode, sizeof(m_customDrmMode)) && m_reservedArea == RULE->reservedArea) {
|
||||
|
||||
Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", m_name);
|
||||
|
||||
|
|
@ -614,17 +614,18 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
|
|||
|
||||
bool autoScale = false;
|
||||
|
||||
if (RULE->scale > 0.1) {
|
||||
if (RULE->scale > 0.1)
|
||||
m_scale = RULE->scale;
|
||||
} else {
|
||||
else {
|
||||
autoScale = true;
|
||||
const auto DEFAULTSCALE = getDefaultScale();
|
||||
m_scale = DEFAULTSCALE;
|
||||
}
|
||||
|
||||
m_setScale = m_scale;
|
||||
m_transform = RULE->transform;
|
||||
m_autoDir = RULE->autoDir;
|
||||
m_setScale = m_scale;
|
||||
m_transform = RULE->transform;
|
||||
m_autoDir = RULE->autoDir;
|
||||
m_reservedArea = RULE->reservedArea;
|
||||
|
||||
// accumulate requested modes in reverse order (cause inesrting at front is inefficient)
|
||||
std::vector<SP<Aquamarine::SOutputMode>> requestedModes;
|
||||
|
|
@ -1517,8 +1518,8 @@ CBox CMonitor::logicalBox() {
|
|||
return {m_position, m_size};
|
||||
}
|
||||
|
||||
CBox CMonitor::logicalBoxMinusExtents() {
|
||||
return {m_position + m_reservedTopLeft, m_size - m_reservedTopLeft - m_reservedBottomRight};
|
||||
CBox CMonitor::logicalBoxMinusReserved() {
|
||||
return m_reservedArea.apply(logicalBox());
|
||||
}
|
||||
|
||||
void CMonitor::scheduleDone() {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <xf86drmMode.h>
|
||||
#include "time/Timer.hpp"
|
||||
#include "math/Math.hpp"
|
||||
#include "../desktop/reserved/ReservedArea.hpp"
|
||||
#include <optional>
|
||||
#include "../protocols/types/ColorManagement.hpp"
|
||||
#include "signal/Signal.hpp"
|
||||
|
|
@ -37,25 +38,26 @@ enum eAutoDirs : uint8_t {
|
|||
};
|
||||
|
||||
struct SMonitorRule {
|
||||
eAutoDirs autoDir = DIR_AUTO_NONE;
|
||||
std::string name = "";
|
||||
Vector2D resolution = Vector2D(1280, 720);
|
||||
Vector2D offset = Vector2D(0, 0);
|
||||
float scale = 1;
|
||||
float refreshRate = 60; // Hz
|
||||
bool disabled = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
std::string mirrorOf = "";
|
||||
bool enable10bit = false;
|
||||
NCMType::eCMType cmType = NCMType::CM_SRGB;
|
||||
int sdrEotf = 0;
|
||||
float sdrSaturation = 1.0f; // SDR -> HDR
|
||||
float sdrBrightness = 1.0f; // SDR -> HDR
|
||||
eAutoDirs autoDir = DIR_AUTO_NONE;
|
||||
std::string name = "";
|
||||
Vector2D resolution = Vector2D(1280, 720);
|
||||
Vector2D offset = Vector2D(0, 0);
|
||||
float scale = 1;
|
||||
float refreshRate = 60; // Hz
|
||||
bool disabled = false;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
std::string mirrorOf = "";
|
||||
bool enable10bit = false;
|
||||
NCMType::eCMType cmType = NCMType::CM_SRGB;
|
||||
int sdrEotf = 0;
|
||||
float sdrSaturation = 1.0f; // SDR -> HDR
|
||||
float sdrBrightness = 1.0f; // SDR -> HDR
|
||||
Desktop::CReservedArea reservedArea;
|
||||
|
||||
bool supportsWideColor = false; // false does nothing, true overrides EDID
|
||||
bool supportsHDR = false; // false does nothing, true overrides EDID
|
||||
float sdrMinLuminance = 0.2f; // SDR -> HDR
|
||||
int sdrMaxLuminance = 80; // SDR -> HDR
|
||||
bool supportsWideColor = false; // false does nothing, true overrides EDID
|
||||
bool supportsHDR = false; // false does nothing, true overrides EDID
|
||||
float sdrMinLuminance = 0.2f; // SDR -> HDR
|
||||
int sdrMaxLuminance = 80; // SDR -> HDR
|
||||
|
||||
// Incorrect values will result in reduced luminance range or incorrect tonemapping. Shouldn't damage the HW. Use with care in case of a faulty monitor firmware.
|
||||
float minLuminance = -1.0f; // >= 0 overrides EDID
|
||||
|
|
@ -108,11 +110,10 @@ class CMonitor {
|
|||
std::string m_description = "";
|
||||
std::string m_shortDescription = "";
|
||||
|
||||
Vector2D m_reservedTopLeft = Vector2D(0, 0);
|
||||
Vector2D m_reservedBottomRight = Vector2D(0, 0);
|
||||
|
||||
drmModeModeInfo m_customDrmMode = {};
|
||||
|
||||
Desktop::CReservedArea m_reservedArea;
|
||||
|
||||
CMonitorState m_state;
|
||||
CDamageRing m_damage;
|
||||
|
||||
|
|
@ -298,7 +299,7 @@ class CMonitor {
|
|||
WORKSPACEID activeWorkspaceID();
|
||||
WORKSPACEID activeSpecialWorkspaceID();
|
||||
CBox logicalBox();
|
||||
CBox logicalBoxMinusExtents();
|
||||
CBox logicalBoxMinusReserved();
|
||||
void scheduleDone();
|
||||
uint32_t isSolitaryBlocked(bool full = false);
|
||||
void recheckSolitary();
|
||||
|
|
|
|||
|
|
@ -162,7 +162,15 @@ void CHyprError::createQueued() {
|
|||
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id);
|
||||
for (const auto& m : g_pCompositor->m_monitors) {
|
||||
m->m_reservedArea.resetType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR);
|
||||
}
|
||||
|
||||
PMONITOR->m_reservedArea.addType(Desktop::RESERVED_DYNAMIC_TYPE_ERROR_BAR, Vector2D{0.0, *BAR_POSITION == 0 ? HEIGHT : 0.0}, Vector2D{0.0, *BAR_POSITION != 0 ? HEIGHT : 0.0});
|
||||
|
||||
for (const auto& m : g_pCompositor->m_monitors) {
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(m->m_id);
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprError::draw() {
|
||||
|
|
|
|||
|
|
@ -41,35 +41,39 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
|
|||
children[0]->recalcSizePosRecursive(force);
|
||||
children[1]->recalcSizePosRecursive(force);
|
||||
} else {
|
||||
layout->applyNodeDataToWindow(this, force);
|
||||
layout->applyNodeDataToWindow(self.lock(), force);
|
||||
}
|
||||
}
|
||||
|
||||
void SDwindleNodeData::applyRootBox() {
|
||||
box = layout->workAreaOnWorkspace(g_pCompositor->getWorkspaceByID(workspaceID));
|
||||
}
|
||||
|
||||
int CHyprDwindleLayout::getNodesOnWorkspace(const WORKSPACEID& id) {
|
||||
int no = 0;
|
||||
for (auto const& n : m_dwindleNodesData) {
|
||||
if (n.workspaceID == id && n.valid)
|
||||
if (n->workspaceID == id && n->valid)
|
||||
++no;
|
||||
}
|
||||
return no;
|
||||
}
|
||||
|
||||
SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const WORKSPACEID& id) {
|
||||
SP<SDwindleNodeData> CHyprDwindleLayout::getFirstNodeOnWorkspace(const WORKSPACEID& id) {
|
||||
for (auto& n : m_dwindleNodesData) {
|
||||
if (n.workspaceID == id && validMapped(n.pWindow))
|
||||
return &n;
|
||||
if (n->workspaceID == id && validMapped(n->pWindow))
|
||||
return n;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const WORKSPACEID& id, const Vector2D& point) {
|
||||
SDwindleNodeData* res = nullptr;
|
||||
double distClosest = -1;
|
||||
SP<SDwindleNodeData> CHyprDwindleLayout::getClosestNodeOnWorkspace(const WORKSPACEID& id, const Vector2D& point) {
|
||||
SP<SDwindleNodeData> res = nullptr;
|
||||
double distClosest = -1;
|
||||
for (auto& n : m_dwindleNodesData) {
|
||||
if (n.workspaceID == id && validMapped(n.pWindow)) {
|
||||
auto distAnother = vecToRectDistanceSquared(point, n.box.pos(), n.box.pos() + n.box.size());
|
||||
if (n->workspaceID == id && validMapped(n->pWindow)) {
|
||||
auto distAnother = vecToRectDistanceSquared(point, n->box.pos(), n->box.pos() + n->box.size());
|
||||
if (!res || distAnother < distClosest) {
|
||||
res = &n;
|
||||
res = n;
|
||||
distClosest = distAnother;
|
||||
}
|
||||
}
|
||||
|
|
@ -77,30 +81,32 @@ SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const WORKSPACEI
|
|||
return res;
|
||||
}
|
||||
|
||||
SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(PHLWINDOW pWindow) {
|
||||
SP<SDwindleNodeData> CHyprDwindleLayout::getNodeFromWindow(PHLWINDOW pWindow) {
|
||||
for (auto& n : m_dwindleNodesData) {
|
||||
if (n.pWindow.lock() == pWindow && !n.isNode)
|
||||
return &n;
|
||||
if (n->pWindow.lock() == pWindow && !n->isNode)
|
||||
return n;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const WORKSPACEID& id) {
|
||||
SP<SDwindleNodeData> CHyprDwindleLayout::getMasterNodeOnWorkspace(const WORKSPACEID& id) {
|
||||
for (auto& n : m_dwindleNodesData) {
|
||||
if (!n.pParent && n.workspaceID == id)
|
||||
return &n;
|
||||
if (!n->pParent && n->workspaceID == id)
|
||||
return n;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool force) {
|
||||
void CHyprDwindleLayout::applyNodeDataToWindow(SP<SDwindleNodeData> pNode, bool force) {
|
||||
// Don't set nodes, only windows.
|
||||
if (pNode->isNode)
|
||||
return;
|
||||
|
||||
PHLMONITOR PMONITOR = nullptr;
|
||||
|
||||
const auto WS = g_pCompositor->getWorkspaceByID(pNode->workspaceID);
|
||||
|
||||
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
|
||||
for (auto const& m : g_pCompositor->m_monitors) {
|
||||
if (m->activeSpecialWorkspaceID() == pNode->workspaceID) {
|
||||
|
|
@ -108,19 +114,20 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else if (const auto WS = g_pCompositor->getWorkspaceByID(pNode->workspaceID); WS)
|
||||
} else if (WS)
|
||||
PMONITOR = WS->m_monitor.lock();
|
||||
|
||||
if (!PMONITOR) {
|
||||
if (!PMONITOR || !WS) {
|
||||
Debug::log(ERR, "Orphaned Node {}!!", pNode);
|
||||
return;
|
||||
}
|
||||
|
||||
// for gaps outer
|
||||
const bool DISPLAYLEFT = STICKS(pNode->box.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x);
|
||||
const bool DISPLAYRIGHT = STICKS(pNode->box.x + pNode->box.w, PMONITOR->m_position.x + PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x);
|
||||
const bool DISPLAYTOP = STICKS(pNode->box.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(pNode->box.y + pNode->box.h, PMONITOR->m_position.y + PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y);
|
||||
const auto MONITOR_WORKAREA = workAreaOnWorkspace(WS);
|
||||
const bool DISPLAYLEFT = STICKS(pNode->box.x, MONITOR_WORKAREA.x);
|
||||
const bool DISPLAYRIGHT = STICKS(pNode->box.x + pNode->box.w, MONITOR_WORKAREA.x + MONITOR_WORKAREA.w);
|
||||
const bool DISPLAYTOP = STICKS(pNode->box.y, MONITOR_WORKAREA.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(pNode->box.y + pNode->box.h, MONITOR_WORKAREA.y + MONITOR_WORKAREA.h);
|
||||
|
||||
const auto PWINDOW = pNode->pWindow.lock();
|
||||
// get specific gaps and rules for this workspace,
|
||||
|
|
@ -139,13 +146,10 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
|||
PWINDOW->m_ruleApplicator->resetProps(Desktop::Rule::RULE_PROP_ALL, Desktop::Types::PRIORITY_LAYOUT);
|
||||
PWINDOW->updateWindowData();
|
||||
|
||||
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
|
||||
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
|
||||
auto* const PGAPSIN = sc<CCssGapData*>((PGAPSINDATA.ptr())->getData());
|
||||
auto* const PGAPSOUT = sc<CCssGapData*>((PGAPSOUTDATA.ptr())->getData());
|
||||
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
|
||||
auto* const PGAPSIN = sc<CCssGapData*>((PGAPSINDATA.ptr())->getData());
|
||||
|
||||
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
|
||||
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
|
||||
CBox nodeBox = pNode->box;
|
||||
nodeBox.round();
|
||||
|
||||
|
|
@ -163,7 +167,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
|||
Vector2D ratioPadding;
|
||||
|
||||
if ((*REQUESTEDRATIO).y != 0 && !pNode->pParent) {
|
||||
const Vector2D originalSize = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight;
|
||||
const Vector2D originalSize = MONITOR_WORKAREA.size();
|
||||
|
||||
const double requestedRatio = (*REQUESTEDRATIO).x / (*REQUESTEDRATIO).y;
|
||||
const double originalRatio = originalSize.x / originalSize.y;
|
||||
|
|
@ -181,9 +185,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
|||
}
|
||||
}
|
||||
|
||||
const auto GAPOFFSETTOPLEFT = Vector2D(sc<double>(DISPLAYLEFT ? gapsOut.m_left : gapsIn.m_left), sc<double>(DISPLAYTOP ? gapsOut.m_top : gapsIn.m_top));
|
||||
const auto GAPOFFSETTOPLEFT = Vector2D(sc<double>(DISPLAYLEFT ? 0 : gapsIn.m_left), sc<double>(DISPLAYTOP ? 0 : gapsIn.m_top));
|
||||
|
||||
const auto GAPOFFSETBOTTOMRIGHT = Vector2D(sc<double>(DISPLAYRIGHT ? gapsOut.m_right : gapsIn.m_right), sc<double>(DISPLAYBOTTOM ? gapsOut.m_bottom : gapsIn.m_bottom));
|
||||
const auto GAPOFFSETBOTTOMRIGHT = Vector2D(sc<double>(DISPLAYRIGHT ? 0 : gapsIn.m_right), sc<double>(DISPLAYBOTTOM ? 0 : gapsIn.m_bottom));
|
||||
|
||||
calcPos = calcPos + GAPOFFSETTOPLEFT + ratioPadding / 2;
|
||||
calcSize = calcSize - GAPOFFSETTOPLEFT - GAPOFFSETBOTTOMRIGHT - ratioPadding;
|
||||
|
|
@ -222,20 +226,17 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
|
|||
|
||||
if (*PCLAMP_TILED) {
|
||||
const auto borderSize = PWINDOW->getRealBorderSize();
|
||||
Vector2D monitorAvailable = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight -
|
||||
Vector2D{(double)(gapsOut.m_left + gapsOut.m_right), (double)(gapsOut.m_top + gapsOut.m_bottom)} - Vector2D{2.0 * borderSize, 2.0 * borderSize};
|
||||
Vector2D monitorAvailable = MONITOR_WORKAREA.size() - Vector2D{2.0 * borderSize, 2.0 * borderSize};
|
||||
|
||||
Vector2D minSize = PWINDOW->m_ruleApplicator->minSize().valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}).clamp(Vector2D{0, 0}, monitorAvailable);
|
||||
Vector2D maxSize = PWINDOW->isFullscreen() ? Vector2D{INFINITY, INFINITY} :
|
||||
PWINDOW->m_ruleApplicator->maxSize().valueOr(Vector2D{INFINITY, INFINITY}).clamp(Vector2D{0, 0}, monitorAvailable);
|
||||
calcSize = calcSize.clamp(minSize, maxSize);
|
||||
Vector2D minSize = PWINDOW->m_ruleApplicator->minSize().valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}).clamp(Vector2D{0, 0}, monitorAvailable);
|
||||
Vector2D maxSize = PWINDOW->isFullscreen() ? Vector2D{INFINITY, INFINITY} :
|
||||
PWINDOW->m_ruleApplicator->maxSize().valueOr(Vector2D{INFINITY, INFINITY}).clamp(Vector2D{0, 0}, monitorAvailable);
|
||||
calcSize = calcSize.clamp(minSize, maxSize);
|
||||
|
||||
calcPos += (availableSpace - calcSize) / 2.0;
|
||||
|
||||
calcPos.x = std::clamp(calcPos.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x + gapsOut.m_left + borderSize,
|
||||
PMONITOR->m_size.x + PMONITOR->m_position.x - PMONITOR->m_reservedBottomRight.x - gapsOut.m_right - calcSize.x - borderSize);
|
||||
calcPos.y = std::clamp(calcPos.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y + gapsOut.m_top + borderSize,
|
||||
PMONITOR->m_size.y + PMONITOR->m_position.y - PMONITOR->m_reservedBottomRight.y - gapsOut.m_bottom - calcSize.y - borderSize);
|
||||
calcPos.x = std::clamp(calcPos.x, MONITOR_WORKAREA.x + borderSize, MONITOR_WORKAREA.x + MONITOR_WORKAREA.w - calcSize.x - borderSize);
|
||||
calcPos.y = std::clamp(calcPos.y, MONITOR_WORKAREA.y + borderSize, MONITOR_WORKAREA.y + MONITOR_WORKAREA.h - calcSize.y - borderSize);
|
||||
}
|
||||
|
||||
if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) {
|
||||
|
|
@ -271,8 +272,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
|
|||
if (pWindow->m_isFloating)
|
||||
return;
|
||||
|
||||
m_dwindleNodesData.emplace_back();
|
||||
const auto PNODE = &m_dwindleNodesData.back();
|
||||
const auto PNODE = m_dwindleNodesData.emplace_back(makeShared<SDwindleNodeData>());
|
||||
PNODE->self = PNODE;
|
||||
|
||||
const auto PMONITOR = pWindow->m_monitor.lock();
|
||||
|
||||
|
|
@ -288,10 +289,10 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
|
|||
PNODE->isNode = false;
|
||||
PNODE->layout = this;
|
||||
|
||||
SDwindleNodeData* OPENINGON;
|
||||
SP<SDwindleNodeData> OPENINGON;
|
||||
|
||||
const auto MOUSECOORDS = m_overrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
|
||||
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
|
||||
const auto MOUSECOORDS = m_overrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
|
||||
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
|
||||
|
||||
if (PMONITOR->m_id == MONFROMCURSOR->m_id &&
|
||||
(PNODE->workspaceID == PMONITOR->activeWorkspaceID() || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->m_activeSpecialWorkspace)) && !*PUSEACTIVE) {
|
||||
|
|
@ -326,7 +327,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
|
|||
if (const auto MAXSIZE = pWindow->requestedMaxSize(); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) {
|
||||
// we can't continue. make it floating.
|
||||
pWindow->m_isFloating = true;
|
||||
m_dwindleNodesData.remove(*PNODE);
|
||||
std::erase(m_dwindleNodesData, PNODE);
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(pWindow);
|
||||
return;
|
||||
}
|
||||
|
|
@ -334,8 +335,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
|
|||
// last fail-safe to avoid duplicate fullscreens
|
||||
if ((!OPENINGON || OPENINGON->pWindow.lock() == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) {
|
||||
for (auto& node : m_dwindleNodesData) {
|
||||
if (node.workspaceID == PNODE->workspaceID && node.pWindow.lock() && node.pWindow.lock() != pWindow) {
|
||||
OPENINGON = &node;
|
||||
if (node->workspaceID == PNODE->workspaceID && node->pWindow.lock() && node->pWindow.lock() != pWindow) {
|
||||
OPENINGON = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -343,17 +344,14 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
|
|||
|
||||
// if it's the first, it's easy. Make it fullscreen.
|
||||
if (!OPENINGON || OPENINGON->pWindow.lock() == pWindow) {
|
||||
PNODE->box = CBox{PMONITOR->m_position + PMONITOR->m_reservedTopLeft, PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight};
|
||||
|
||||
PNODE->applyRootBox();
|
||||
applyNodeDataToWindow(PNODE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// get the node under our cursor
|
||||
|
||||
m_dwindleNodesData.emplace_back();
|
||||
const auto NEWPARENT = &m_dwindleNodesData.back();
|
||||
const auto NEWPARENT = m_dwindleNodesData.emplace_back(makeShared<SDwindleNodeData>());
|
||||
|
||||
// make the parent have the OPENINGON's stats
|
||||
NEWPARENT->box = OPENINGON->box;
|
||||
|
|
@ -361,6 +359,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
|
|||
NEWPARENT->pParent = OPENINGON->pParent;
|
||||
NEWPARENT->isNode = true; // it is a node
|
||||
NEWPARENT->splitRatio = std::clamp(*PDEFAULTSPLIT, 0.1f, 1.9f);
|
||||
NEWPARENT->layout = this;
|
||||
|
||||
static auto PWIDTHMULTIPLIER = CConfigValue<Hyprlang::FLOAT>("dwindle:split_width_multiplier");
|
||||
|
||||
|
|
@ -503,7 +502,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
|
|||
|
||||
if (!PPARENT) {
|
||||
Debug::log(LOG, "Removing last node (dwindle)");
|
||||
m_dwindleNodesData.remove(*PNODE);
|
||||
std::erase(m_dwindleNodesData, PNODE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -528,8 +527,8 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
|
|||
else
|
||||
PSIBLING->recalcSizePosRecursive();
|
||||
|
||||
m_dwindleNodesData.remove(*PPARENT);
|
||||
m_dwindleNodesData.remove(*PNODE);
|
||||
std::erase(m_dwindleNodesData, PPARENT);
|
||||
std::erase(m_dwindleNodesData, PNODE);
|
||||
pWindow->m_workspace->updateWindows();
|
||||
}
|
||||
|
||||
|
|
@ -568,15 +567,17 @@ void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) {
|
|||
*PFULLWINDOW->m_realPosition = PMONITOR->m_position;
|
||||
*PFULLWINDOW->m_realSize = PMONITOR->m_size;
|
||||
} else if (pWorkspace->m_fullscreenMode == FSMODE_MAXIMIZED) {
|
||||
SDwindleNodeData fakeNode;
|
||||
fakeNode.pWindow = PFULLWINDOW;
|
||||
fakeNode.box = {PMONITOR->m_position + PMONITOR->m_reservedTopLeft, PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight};
|
||||
fakeNode.workspaceID = pWorkspace->m_id;
|
||||
PFULLWINDOW->m_position = fakeNode.box.pos();
|
||||
PFULLWINDOW->m_size = fakeNode.box.size();
|
||||
fakeNode.ignoreFullscreenChecks = true;
|
||||
SP<SDwindleNodeData> fakeNode = makeShared<SDwindleNodeData>();
|
||||
fakeNode->self = fakeNode;
|
||||
fakeNode->pWindow = PFULLWINDOW;
|
||||
fakeNode->box = PMONITOR->logicalBoxMinusReserved();
|
||||
fakeNode->workspaceID = pWorkspace->m_id;
|
||||
PFULLWINDOW->m_position = fakeNode->box.pos();
|
||||
PFULLWINDOW->m_size = fakeNode->box.size();
|
||||
fakeNode->ignoreFullscreenChecks = true;
|
||||
fakeNode->layout = this;
|
||||
|
||||
applyNodeDataToWindow(&fakeNode);
|
||||
applyNodeDataToWindow(fakeNode);
|
||||
}
|
||||
|
||||
// if has fullscreen, don't calculate the rest
|
||||
|
|
@ -586,7 +587,7 @@ void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) {
|
|||
const auto TOPNODE = getMasterNodeOnWorkspace(pWorkspace->m_id);
|
||||
|
||||
if (TOPNODE) {
|
||||
TOPNODE->box = {PMONITOR->m_position + PMONITOR->m_reservedTopLeft, PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight};
|
||||
TOPNODE->applyRootBox();
|
||||
TOPNODE->recalcSizePosRecursive();
|
||||
}
|
||||
}
|
||||
|
|
@ -622,11 +623,12 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
|
|||
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("dwindle:smart_resizing");
|
||||
|
||||
// get some data about our window
|
||||
const auto PMONITOR = PWINDOW->m_monitor.lock();
|
||||
const bool DISPLAYLEFT = STICKS(PWINDOW->m_position.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x);
|
||||
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_position.x + PWINDOW->m_size.x, PMONITOR->m_position.x + PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x);
|
||||
const bool DISPLAYTOP = STICKS(PWINDOW->m_position.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_position.y + PWINDOW->m_size.y, PMONITOR->m_position.y + PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y);
|
||||
const auto PMONITOR = PWINDOW->m_monitor.lock();
|
||||
const auto MONITOR_WORKAREA = PMONITOR->logicalBoxMinusReserved();
|
||||
const bool DISPLAYLEFT = STICKS(PWINDOW->m_position.x, MONITOR_WORKAREA.x);
|
||||
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_position.x + PWINDOW->m_size.x, MONITOR_WORKAREA.x + MONITOR_WORKAREA.w);
|
||||
const bool DISPLAYTOP = STICKS(PWINDOW->m_position.y, MONITOR_WORKAREA.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_position.y + PWINDOW->m_size.y, MONITOR_WORKAREA.y + MONITOR_WORKAREA.h);
|
||||
|
||||
if (PWINDOW->m_isPseudotiled) {
|
||||
if (!m_pseudoDragFlags.started) {
|
||||
|
|
@ -682,18 +684,18 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
|
|||
|
||||
if (*PSMARTRESIZING == 1) {
|
||||
// Identify inner and outer nodes for both directions
|
||||
SDwindleNodeData* PVOUTER = nullptr;
|
||||
SDwindleNodeData* PVINNER = nullptr;
|
||||
SDwindleNodeData* PHOUTER = nullptr;
|
||||
SDwindleNodeData* PHINNER = nullptr;
|
||||
SP<SDwindleNodeData> PVOUTER = nullptr;
|
||||
SP<SDwindleNodeData> PVINNER = nullptr;
|
||||
SP<SDwindleNodeData> PHOUTER = nullptr;
|
||||
SP<SDwindleNodeData> PHINNER = nullptr;
|
||||
|
||||
const auto LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT || DISPLAYRIGHT;
|
||||
const auto TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT || DISPLAYBOTTOM;
|
||||
const auto RIGHT = corner == CORNER_TOPRIGHT || corner == CORNER_BOTTOMRIGHT || DISPLAYLEFT;
|
||||
const auto BOTTOM = corner == CORNER_BOTTOMLEFT || corner == CORNER_BOTTOMRIGHT || DISPLAYTOP;
|
||||
const auto NONE = corner == CORNER_NONE;
|
||||
const auto LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT || DISPLAYRIGHT;
|
||||
const auto TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT || DISPLAYBOTTOM;
|
||||
const auto RIGHT = corner == CORNER_TOPRIGHT || corner == CORNER_BOTTOMRIGHT || DISPLAYLEFT;
|
||||
const auto BOTTOM = corner == CORNER_BOTTOMLEFT || corner == CORNER_BOTTOMRIGHT || DISPLAYTOP;
|
||||
const auto NONE = corner == CORNER_NONE;
|
||||
|
||||
for (auto PCURRENT = PNODE; PCURRENT && PCURRENT->pParent; PCURRENT = PCURRENT->pParent) {
|
||||
for (auto PCURRENT = PNODE; PCURRENT && PCURRENT->pParent; PCURRENT = PCURRENT->pParent.lock()) {
|
||||
const auto PPARENT = PCURRENT->pParent;
|
||||
|
||||
if (!PVOUTER && PPARENT->splitTop && (NONE || (TOP && PPARENT->children[1] == PCURRENT) || (BOTTOM && PPARENT->children[0] == PCURRENT)))
|
||||
|
|
@ -833,15 +835,17 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFu
|
|||
// We make a fake "only" node and apply
|
||||
// To keep consistent with the settings without C+P code
|
||||
|
||||
SDwindleNodeData fakeNode;
|
||||
fakeNode.pWindow = pWindow;
|
||||
fakeNode.box = {PMONITOR->m_position + PMONITOR->m_reservedTopLeft, PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight};
|
||||
fakeNode.workspaceID = pWindow->workspaceID();
|
||||
pWindow->m_position = fakeNode.box.pos();
|
||||
pWindow->m_size = fakeNode.box.size();
|
||||
fakeNode.ignoreFullscreenChecks = true;
|
||||
SP<SDwindleNodeData> fakeNode = makeShared<SDwindleNodeData>();
|
||||
fakeNode->self = fakeNode;
|
||||
fakeNode->pWindow = pWindow;
|
||||
fakeNode->box = PMONITOR->logicalBoxMinusReserved();
|
||||
fakeNode->workspaceID = pWindow->workspaceID();
|
||||
pWindow->m_position = fakeNode->box.pos();
|
||||
pWindow->m_size = fakeNode->box.size();
|
||||
fakeNode->ignoreFullscreenChecks = true;
|
||||
fakeNode->layout = this;
|
||||
|
||||
applyNodeDataToWindow(&fakeNode);
|
||||
applyNodeDataToWindow(fakeNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1092,10 +1096,10 @@ void CHyprDwindleLayout::moveToRoot(PHLWINDOW pWindow, bool stable) {
|
|||
|
||||
// instead of [getMasterNodeOnWorkspace], we walk back to root since we need
|
||||
// to know which children of root is our ancestor
|
||||
auto pAncestor = PNODE, pRoot = PNODE->pParent;
|
||||
auto pAncestor = PNODE, pRoot = PNODE->pParent.lock();
|
||||
while (pRoot->pParent) {
|
||||
pAncestor = pRoot;
|
||||
pRoot = pRoot->pParent;
|
||||
pRoot = pRoot->pParent.lock();
|
||||
}
|
||||
|
||||
auto& pSwap = pRoot->children[0] == pAncestor ? pRoot->children[1] : pRoot->children[0];
|
||||
|
|
|
|||
|
|
@ -13,24 +13,25 @@ class CHyprDwindleLayout;
|
|||
enum eFullscreenMode : int8_t;
|
||||
|
||||
struct SDwindleNodeData {
|
||||
SDwindleNodeData* pParent = nullptr;
|
||||
bool isNode = false;
|
||||
WP<SDwindleNodeData> pParent;
|
||||
bool isNode = false;
|
||||
|
||||
PHLWINDOWREF pWindow;
|
||||
PHLWINDOWREF pWindow;
|
||||
|
||||
std::array<SDwindleNodeData*, 2> children = {nullptr, nullptr};
|
||||
std::array<WP<SDwindleNodeData>, 2> children = {};
|
||||
WP<SDwindleNodeData> self;
|
||||
|
||||
bool splitTop = false; // for preserve_split
|
||||
bool splitTop = false; // for preserve_split
|
||||
|
||||
CBox box = {0};
|
||||
CBox box = {0};
|
||||
|
||||
WORKSPACEID workspaceID = WORKSPACE_INVALID;
|
||||
WORKSPACEID workspaceID = WORKSPACE_INVALID;
|
||||
|
||||
float splitRatio = 1.f;
|
||||
float splitRatio = 1.f;
|
||||
|
||||
bool valid = true;
|
||||
bool valid = true;
|
||||
|
||||
bool ignoreFullscreenChecks = false;
|
||||
bool ignoreFullscreenChecks = false;
|
||||
|
||||
// For list lookup
|
||||
bool operator==(const SDwindleNodeData& rhs) const {
|
||||
|
|
@ -39,6 +40,7 @@ struct SDwindleNodeData {
|
|||
}
|
||||
|
||||
void recalcSizePosRecursive(bool force = false, bool horizontalOverride = false, bool verticalOverride = false);
|
||||
void applyRootBox();
|
||||
CHyprDwindleLayout* layout = nullptr;
|
||||
};
|
||||
|
||||
|
|
@ -65,7 +67,7 @@ class CHyprDwindleLayout : public IHyprLayout {
|
|||
virtual void onDisable();
|
||||
|
||||
private:
|
||||
std::list<SDwindleNodeData> m_dwindleNodesData;
|
||||
std::vector<SP<SDwindleNodeData>> m_dwindleNodesData;
|
||||
|
||||
struct {
|
||||
bool started = false;
|
||||
|
|
@ -77,12 +79,12 @@ class CHyprDwindleLayout : public IHyprLayout {
|
|||
std::optional<Vector2D> m_overrideFocalPoint; // for onWindowCreatedTiling.
|
||||
|
||||
int getNodesOnWorkspace(const WORKSPACEID&);
|
||||
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
|
||||
void applyNodeDataToWindow(SP<SDwindleNodeData>, bool force = false);
|
||||
void calculateWorkspace(const PHLWORKSPACE& pWorkspace);
|
||||
SDwindleNodeData* getNodeFromWindow(PHLWINDOW);
|
||||
SDwindleNodeData* getFirstNodeOnWorkspace(const WORKSPACEID&);
|
||||
SDwindleNodeData* getClosestNodeOnWorkspace(const WORKSPACEID&, const Vector2D&);
|
||||
SDwindleNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&);
|
||||
SP<SDwindleNodeData> getNodeFromWindow(PHLWINDOW);
|
||||
SP<SDwindleNodeData> getFirstNodeOnWorkspace(const WORKSPACEID&);
|
||||
SP<SDwindleNodeData> getClosestNodeOnWorkspace(const WORKSPACEID&, const Vector2D&);
|
||||
SP<SDwindleNodeData> getMasterNodeOnWorkspace(const WORKSPACEID&);
|
||||
|
||||
void toggleSplit(PHLWINDOW);
|
||||
void swapSplit(PHLWINDOW);
|
||||
|
|
@ -94,13 +96,13 @@ class CHyprDwindleLayout : public IHyprLayout {
|
|||
};
|
||||
|
||||
template <typename CharT>
|
||||
struct std::formatter<SDwindleNodeData*, CharT> : std::formatter<CharT> {
|
||||
struct std::formatter<SP<SDwindleNodeData>, CharT> : std::formatter<CharT> {
|
||||
template <typename FormatContext>
|
||||
auto format(const SDwindleNodeData* const& node, FormatContext& ctx) const {
|
||||
auto format(const SP<SDwindleNodeData>& node, FormatContext& ctx) const {
|
||||
auto out = ctx.out();
|
||||
if (!node)
|
||||
return std::format_to(out, "[Node nullptr]");
|
||||
std::format_to(out, "[Node {:x}: workspace: {}, pos: {:j2}, size: {:j2}", rc<uintptr_t>(node), node->workspaceID, node->box.pos(), node->box.size());
|
||||
std::format_to(out, "[Node {:x}: workspace: {}, pos: {:j2}, size: {:j2}", rc<uintptr_t>(node.get()), node->workspaceID, node->box.pos(), node->box.size());
|
||||
if (!node->isNode && !node->pWindow.expired())
|
||||
std::format_to(out, ", window: {:x}", node->pWindow.lock());
|
||||
return std::format_to(out, "]");
|
||||
|
|
|
|||
|
|
@ -503,32 +503,35 @@ void IHyprLayout::performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWIND
|
|||
const auto EXTENTNONE = SBoxExtents{{0, 0}, {0, 0}};
|
||||
const auto* EXTENTDIFF = *SNAPBORDEROVERLAP ? &EXTENTS : &EXTENTNONE;
|
||||
const auto MON = DRAGGINGWINDOW->m_monitor.lock();
|
||||
const auto* GAPSOUT = *SNAPRESPECTGAPS ? sc<CCssGapData*>(PGAPSOUT.ptr()->getData()) : &GAPSNONE;
|
||||
|
||||
SRange monX = {MON->m_position.x + MON->m_reservedTopLeft.x + GAPSOUT->m_left, MON->m_position.x + MON->m_size.x - MON->m_reservedBottomRight.x - GAPSOUT->m_right};
|
||||
SRange monY = {MON->m_position.y + MON->m_reservedTopLeft.y + GAPSOUT->m_top, MON->m_position.y + MON->m_size.y - MON->m_reservedBottomRight.y - GAPSOUT->m_bottom};
|
||||
const auto* GAPSOUT = *SNAPRESPECTGAPS ? sc<CCssGapData*>(PGAPSOUT.ptr()->getData()) : &GAPSNONE;
|
||||
const auto WORK_AREA = Desktop::CReservedArea{GAPSOUT->m_top, GAPSOUT->m_right, GAPSOUT->m_bottom, GAPSOUT->m_left}.apply(MON->logicalBoxMinusReserved());
|
||||
|
||||
SRange monX = {WORK_AREA.x, WORK_AREA.x + WORK_AREA.w};
|
||||
SRange monY = {WORK_AREA.y, WORK_AREA.y + WORK_AREA.h};
|
||||
|
||||
const bool HAS_LEFT = MON->m_reservedArea.left() > 0;
|
||||
const bool HAS_TOP = MON->m_reservedArea.top() > 0;
|
||||
const bool HAS_BOTTOM = MON->m_reservedArea.bottom() > 0;
|
||||
const bool HAS_RIGHT = MON->m_reservedArea.right() > 0;
|
||||
|
||||
if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) &&
|
||||
((MON->m_reservedTopLeft.x > 0 && canSnap(sourceX.start, monX.start, GAPSIZE)) ||
|
||||
canSnap(sourceX.start, (monX.start -= MON->m_reservedTopLeft.x + EXTENTDIFF->topLeft.x), GAPSIZE))) {
|
||||
((HAS_LEFT && canSnap(sourceX.start, monX.start, GAPSIZE)) || canSnap(sourceX.start, (monX.start -= MON->m_reservedArea.left() + EXTENTDIFF->topLeft.x), GAPSIZE))) {
|
||||
SNAP(sourceX.start, sourceX.end, monX.start);
|
||||
snaps |= SNAP_LEFT;
|
||||
}
|
||||
if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) &&
|
||||
((MON->m_reservedBottomRight.x > 0 && canSnap(sourceX.end, monX.end, GAPSIZE)) ||
|
||||
canSnap(sourceX.end, (monX.end += MON->m_reservedBottomRight.x + EXTENTDIFF->bottomRight.x), GAPSIZE))) {
|
||||
((HAS_RIGHT && canSnap(sourceX.end, monX.end, GAPSIZE)) || canSnap(sourceX.end, (monX.end += MON->m_reservedArea.right() + EXTENTDIFF->bottomRight.x), GAPSIZE))) {
|
||||
SNAP(sourceX.end, sourceX.start, monX.end);
|
||||
snaps |= SNAP_RIGHT;
|
||||
}
|
||||
if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) &&
|
||||
((MON->m_reservedTopLeft.y > 0 && canSnap(sourceY.start, monY.start, GAPSIZE)) ||
|
||||
canSnap(sourceY.start, (monY.start -= MON->m_reservedTopLeft.y + EXTENTDIFF->topLeft.y), GAPSIZE))) {
|
||||
((HAS_TOP && canSnap(sourceY.start, monY.start, GAPSIZE)) || canSnap(sourceY.start, (monY.start -= MON->m_reservedArea.top() + EXTENTDIFF->topLeft.y), GAPSIZE))) {
|
||||
SNAP(sourceY.start, sourceY.end, monY.start);
|
||||
snaps |= SNAP_UP;
|
||||
}
|
||||
if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) &&
|
||||
((MON->m_reservedBottomRight.y > 0 && canSnap(sourceY.end, monY.end, GAPSIZE)) ||
|
||||
canSnap(sourceY.end, (monY.end += MON->m_reservedBottomRight.y + EXTENTDIFF->bottomRight.y), GAPSIZE))) {
|
||||
((HAS_BOTTOM && canSnap(sourceY.end, monY.end, GAPSIZE)) || canSnap(sourceY.end, (monY.end += MON->m_reservedArea.bottom() + EXTENTDIFF->bottomRight.y), GAPSIZE))) {
|
||||
SNAP(sourceY.end, sourceY.start, monY.end);
|
||||
snaps |= SNAP_DOWN;
|
||||
}
|
||||
|
|
@ -832,7 +835,7 @@ void IHyprLayout::fitFloatingWindowOnMonitor(PHLWINDOW w, std::optional<CBox> tb
|
|||
|
||||
const auto EXTENTS = w->getWindowExtentsUnified(RESERVED_EXTENTS | INPUT_EXTENTS);
|
||||
CBox targetBoxMonLocal = tb.value_or(w->getWindowMainSurfaceBox()).translate(-PMONITOR->m_position).addExtents(EXTENTS);
|
||||
const auto MONITOR_LOCAL_BOX = PMONITOR->logicalBoxMinusExtents().translate(-PMONITOR->m_position);
|
||||
const auto MONITOR_LOCAL_BOX = PMONITOR->logicalBoxMinusReserved().translate(-PMONITOR->m_position);
|
||||
|
||||
if (targetBoxMonLocal.w < MONITOR_LOCAL_BOX.w) {
|
||||
if (targetBoxMonLocal.x < MONITOR_LOCAL_BOX.x)
|
||||
|
|
@ -1039,3 +1042,22 @@ bool IHyprLayout::updateDragWindow() {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
CBox IHyprLayout::workAreaOnWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
if (!pWorkspace || !pWorkspace->m_monitor)
|
||||
return {};
|
||||
|
||||
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(pWorkspace);
|
||||
|
||||
auto workArea = pWorkspace->m_monitor->logicalBoxMinusReserved();
|
||||
|
||||
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
|
||||
auto* const PGAPSOUT = sc<CCssGapData*>((PGAPSOUTDATA.ptr())->getData());
|
||||
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
|
||||
|
||||
Desktop::CReservedArea reservedGaps{gapsOut.m_top, gapsOut.m_right, gapsOut.m_bottom, gapsOut.m_left};
|
||||
|
||||
reservedGaps.applyip(workArea);
|
||||
|
||||
return workArea;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,6 +230,12 @@ class IHyprLayout {
|
|||
*/
|
||||
virtual void fitFloatingWindowOnMonitor(PHLWINDOW w, std::optional<CBox> targetBox = std::nullopt);
|
||||
|
||||
/*
|
||||
Returns a logical box describing the work area on a workspace
|
||||
(monitor size - reserved - gapsOut)
|
||||
*/
|
||||
virtual CBox workAreaOnWorkspace(const PHLWORKSPACE& pWorkspace);
|
||||
|
||||
private:
|
||||
int m_mouseMoveEventCount;
|
||||
Vector2D m_beginDragXY;
|
||||
|
|
|
|||
|
|
@ -322,8 +322,9 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
} else if (pWorkspace->m_fullscreenMode == FSMODE_MAXIMIZED) {
|
||||
SMasterNodeData fakeNode;
|
||||
fakeNode.pWindow = PFULLWINDOW;
|
||||
fakeNode.position = PMONITOR->m_position + PMONITOR->m_reservedTopLeft;
|
||||
fakeNode.size = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight;
|
||||
const auto WORKAREA = PMONITOR->logicalBoxMinusReserved();
|
||||
fakeNode.position = WORKAREA.pos();
|
||||
fakeNode.size = WORKAREA.size();
|
||||
fakeNode.workspaceID = pWorkspace->m_id;
|
||||
PFULLWINDOW->m_position = fakeNode.position;
|
||||
PFULLWINDOW->m_size = fakeNode.size;
|
||||
|
|
@ -351,13 +352,12 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
const auto MASTERS = getMastersOnWorkspace(pWorkspace->m_id);
|
||||
const auto WINDOWS = getNodesOnWorkspace(pWorkspace->m_id);
|
||||
const auto STACKWINDOWS = WINDOWS - MASTERS;
|
||||
const auto WSSIZE = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight;
|
||||
const auto WSPOS = PMONITOR->m_position + PMONITOR->m_reservedTopLeft;
|
||||
const auto WORKAREA = workAreaOnWorkspace(pWorkspace);
|
||||
|
||||
if (orientation == ORIENTATION_CENTER) {
|
||||
if (STACKWINDOWS >= *SLAVECOUNTFORCENTER) {
|
||||
if (STACKWINDOWS >= *SLAVECOUNTFORCENTER)
|
||||
centerMasterWindow = true;
|
||||
} else {
|
||||
else {
|
||||
if (*CMFALLBACK == "left")
|
||||
orientation = ORIENTATION_LEFT;
|
||||
else if (*CMFALLBACK == "right")
|
||||
|
|
@ -371,7 +371,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
}
|
||||
}
|
||||
|
||||
const float totalSize = (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) ? WSSIZE.x : WSSIZE.y;
|
||||
const float totalSize = (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) ? WORKAREA.w : WORKAREA.h;
|
||||
const float masterAverageSize = totalSize / MASTERS;
|
||||
const float slaveAverageSize = totalSize / STACKWINDOWS;
|
||||
float masterAccumulatedSize = 0;
|
||||
|
|
@ -394,32 +394,32 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
if (WINDOWS == 1 && !centerMasterWindow) {
|
||||
static auto PALWAYSKEEPPOSITION = CConfigValue<Hyprlang::INT>("master:always_keep_position");
|
||||
if (*PALWAYSKEEPPOSITION) {
|
||||
const float WIDTH = WSSIZE.x * PMASTERNODE->percMaster;
|
||||
const float WIDTH = WORKAREA.w * PMASTERNODE->percMaster;
|
||||
float nextX = 0;
|
||||
|
||||
if (orientation == ORIENTATION_RIGHT)
|
||||
nextX = WSSIZE.x - WIDTH;
|
||||
nextX = WORKAREA.w - WIDTH;
|
||||
else if (orientation == ORIENTATION_CENTER)
|
||||
nextX = (WSSIZE.x - WIDTH) / 2;
|
||||
nextX = (WORKAREA.w - WIDTH) / 2;
|
||||
|
||||
PMASTERNODE->size = Vector2D(WIDTH, WSSIZE.y);
|
||||
PMASTERNODE->position = WSPOS + Vector2D(nextX, 0.0);
|
||||
PMASTERNODE->size = Vector2D(WIDTH, WORKAREA.h);
|
||||
PMASTERNODE->position = WORKAREA.pos() + Vector2D(nextX, 0.0);
|
||||
} else {
|
||||
PMASTERNODE->size = WSSIZE;
|
||||
PMASTERNODE->position = WSPOS;
|
||||
PMASTERNODE->size = WORKAREA.size();
|
||||
PMASTERNODE->position = WORKAREA.pos();
|
||||
}
|
||||
|
||||
applyNodeDataToWindow(PMASTERNODE);
|
||||
return;
|
||||
} else if (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) {
|
||||
const float HEIGHT = STACKWINDOWS != 0 ? WSSIZE.y * PMASTERNODE->percMaster : WSSIZE.y;
|
||||
float widthLeft = WSSIZE.x;
|
||||
const float HEIGHT = STACKWINDOWS != 0 ? WORKAREA.h * PMASTERNODE->percMaster : WORKAREA.h;
|
||||
float widthLeft = WORKAREA.w;
|
||||
int mastersLeft = MASTERS;
|
||||
float nextX = 0;
|
||||
float nextY = 0;
|
||||
|
||||
if (orientation == ORIENTATION_BOTTOM)
|
||||
nextY = WSSIZE.y - HEIGHT;
|
||||
nextY = WORKAREA.h - HEIGHT;
|
||||
|
||||
for (auto& nd : m_masterNodesData) {
|
||||
if (nd.workspaceID != pWorkspace->m_id || !nd.isMaster)
|
||||
|
|
@ -430,12 +430,12 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
WIDTH = widthLeft * 0.9f;
|
||||
|
||||
if (*PSMARTRESIZING) {
|
||||
nd.percSize *= WSSIZE.x / masterAccumulatedSize;
|
||||
nd.percSize *= WORKAREA.w / masterAccumulatedSize;
|
||||
WIDTH = masterAverageSize * nd.percSize;
|
||||
}
|
||||
|
||||
nd.size = Vector2D(WIDTH, HEIGHT);
|
||||
nd.position = WSPOS + Vector2D(nextX, nextY);
|
||||
nd.position = WORKAREA.pos() + Vector2D(nextX, nextY);
|
||||
applyNodeDataToWindow(&nd);
|
||||
|
||||
mastersLeft--;
|
||||
|
|
@ -443,8 +443,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
nextX += WIDTH;
|
||||
}
|
||||
} else { // orientation left, right or center
|
||||
float WIDTH = *PIGNORERESERVED && centerMasterWindow ? PMONITOR->m_size.x : WSSIZE.x;
|
||||
float heightLeft = WSSIZE.y;
|
||||
float WIDTH = *PIGNORERESERVED && centerMasterWindow ? PMONITOR->m_size.x : WORKAREA.w;
|
||||
float heightLeft = WORKAREA.h;
|
||||
int mastersLeft = MASTERS;
|
||||
float nextX = 0;
|
||||
float nextY = 0;
|
||||
|
|
@ -452,11 +452,10 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
if (STACKWINDOWS > 0 || centerMasterWindow)
|
||||
WIDTH *= PMASTERNODE->percMaster;
|
||||
|
||||
if (orientation == ORIENTATION_RIGHT) {
|
||||
nextX = WSSIZE.x - WIDTH;
|
||||
} else if (centerMasterWindow) {
|
||||
nextX = ((*PIGNORERESERVED && centerMasterWindow ? PMONITOR->m_size.x : WSSIZE.x) - WIDTH) / 2;
|
||||
}
|
||||
if (orientation == ORIENTATION_RIGHT)
|
||||
nextX = WORKAREA.w - WIDTH;
|
||||
else if (centerMasterWindow)
|
||||
nextX = ((*PIGNORERESERVED && centerMasterWindow ? PMONITOR->m_size.x : WORKAREA.w) - WIDTH) / 2;
|
||||
|
||||
for (auto& nd : m_masterNodesData) {
|
||||
if (nd.workspaceID != pWorkspace->m_id || !nd.isMaster)
|
||||
|
|
@ -467,12 +466,12 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
HEIGHT = heightLeft * 0.9f;
|
||||
|
||||
if (*PSMARTRESIZING) {
|
||||
nd.percSize *= WSSIZE.y / masterAccumulatedSize;
|
||||
nd.percSize *= WORKAREA.h / masterAccumulatedSize;
|
||||
HEIGHT = masterAverageSize * nd.percSize;
|
||||
}
|
||||
|
||||
nd.size = Vector2D(WIDTH, HEIGHT);
|
||||
nd.position = (*PIGNORERESERVED && centerMasterWindow ? PMONITOR->m_position : WSPOS) + Vector2D(nextX, nextY);
|
||||
nd.position = (*PIGNORERESERVED && centerMasterWindow ? PMONITOR->m_position : WORKAREA.pos()) + Vector2D(nextX, nextY);
|
||||
applyNodeDataToWindow(&nd);
|
||||
|
||||
mastersLeft--;
|
||||
|
|
@ -487,8 +486,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
// compute placement of slave window(s)
|
||||
int slavesLeft = STACKWINDOWS;
|
||||
if (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) {
|
||||
const float HEIGHT = WSSIZE.y - PMASTERNODE->size.y;
|
||||
float widthLeft = WSSIZE.x;
|
||||
const float HEIGHT = WORKAREA.h - PMASTERNODE->size.y;
|
||||
float widthLeft = WORKAREA.w;
|
||||
float nextX = 0;
|
||||
float nextY = 0;
|
||||
|
||||
|
|
@ -504,12 +503,12 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
WIDTH = widthLeft * 0.9f;
|
||||
|
||||
if (*PSMARTRESIZING) {
|
||||
nd.percSize *= WSSIZE.x / slaveAccumulatedSize;
|
||||
nd.percSize *= WORKAREA.w / slaveAccumulatedSize;
|
||||
WIDTH = slaveAverageSize * nd.percSize;
|
||||
}
|
||||
|
||||
nd.size = Vector2D(WIDTH, HEIGHT);
|
||||
nd.position = WSPOS + Vector2D(nextX, nextY);
|
||||
nd.position = WORKAREA.pos() + Vector2D(nextX, nextY);
|
||||
applyNodeDataToWindow(&nd);
|
||||
|
||||
slavesLeft--;
|
||||
|
|
@ -517,8 +516,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
nextX += WIDTH;
|
||||
}
|
||||
} else if (orientation == ORIENTATION_LEFT || orientation == ORIENTATION_RIGHT) {
|
||||
const float WIDTH = WSSIZE.x - PMASTERNODE->size.x;
|
||||
float heightLeft = WSSIZE.y;
|
||||
const float WIDTH = WORKAREA.w - PMASTERNODE->size.x;
|
||||
float heightLeft = WORKAREA.h;
|
||||
float nextY = 0;
|
||||
float nextX = 0;
|
||||
|
||||
|
|
@ -534,12 +533,12 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
HEIGHT = heightLeft * 0.9f;
|
||||
|
||||
if (*PSMARTRESIZING) {
|
||||
nd.percSize *= WSSIZE.y / slaveAccumulatedSize;
|
||||
nd.percSize *= WORKAREA.h / slaveAccumulatedSize;
|
||||
HEIGHT = slaveAverageSize * nd.percSize;
|
||||
}
|
||||
|
||||
nd.size = Vector2D(WIDTH, HEIGHT);
|
||||
nd.position = WSPOS + Vector2D(nextX, nextY);
|
||||
nd.position = WORKAREA.pos() + Vector2D(nextX, nextY);
|
||||
applyNodeDataToWindow(&nd);
|
||||
|
||||
slavesLeft--;
|
||||
|
|
@ -547,10 +546,10 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
nextY += HEIGHT;
|
||||
}
|
||||
} else { // slaves for centered master window(s)
|
||||
const float WIDTH = ((*PIGNORERESERVED ? PMONITOR->m_size.x : WSSIZE.x) - PMASTERNODE->size.x) / 2.0;
|
||||
const float WIDTH = ((*PIGNORERESERVED ? PMONITOR->m_size.x : WORKAREA.w) - PMASTERNODE->size.x) / 2.0;
|
||||
float heightLeft = 0;
|
||||
float heightLeftL = WSSIZE.y;
|
||||
float heightLeftR = WSSIZE.y;
|
||||
float heightLeftL = WORKAREA.h;
|
||||
float heightLeftR = WORKAREA.h;
|
||||
float nextX = 0;
|
||||
float nextY = 0;
|
||||
float nextYL = 0;
|
||||
|
|
@ -564,8 +563,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
slavesLeftL = slavesLeft - slavesLeftR;
|
||||
}
|
||||
|
||||
const float slaveAverageHeightL = WSSIZE.y / slavesLeftL;
|
||||
const float slaveAverageHeightR = WSSIZE.y / slavesLeftR;
|
||||
const float slaveAverageHeightL = WORKAREA.h / slavesLeftL;
|
||||
const float slaveAverageHeightR = WORKAREA.h / slavesLeftR;
|
||||
float slaveAccumulatedHeightL = 0;
|
||||
float slaveAccumulatedHeightR = 0;
|
||||
|
||||
|
|
@ -590,7 +589,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
continue;
|
||||
|
||||
if (onRight) {
|
||||
nextX = WIDTH + PMASTERNODE->size.x - (*PIGNORERESERVED ? PMONITOR->m_reservedTopLeft.x : 0);
|
||||
nextX = WIDTH + PMASTERNODE->size.x - (*PIGNORERESERVED ? PMONITOR->m_reservedArea.left() : 0);
|
||||
nextY = nextYR;
|
||||
heightLeft = heightLeftR;
|
||||
slavesLeft = slavesLeftR;
|
||||
|
|
@ -607,16 +606,16 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
|
||||
if (*PSMARTRESIZING) {
|
||||
if (onRight) {
|
||||
nd.percSize *= WSSIZE.y / slaveAccumulatedHeightR;
|
||||
nd.percSize *= WORKAREA.h / slaveAccumulatedHeightR;
|
||||
HEIGHT = slaveAverageHeightR * nd.percSize;
|
||||
} else {
|
||||
nd.percSize *= WSSIZE.y / slaveAccumulatedHeightL;
|
||||
nd.percSize *= WORKAREA.h / slaveAccumulatedHeightL;
|
||||
HEIGHT = slaveAverageHeightL * nd.percSize;
|
||||
}
|
||||
}
|
||||
|
||||
nd.size = Vector2D(*PIGNORERESERVED ? (WIDTH - (onRight ? PMONITOR->m_reservedBottomRight.x : PMONITOR->m_reservedTopLeft.x)) : WIDTH, HEIGHT);
|
||||
nd.position = WSPOS + Vector2D(nextX, nextY);
|
||||
nd.size = Vector2D(*PIGNORERESERVED ? (WIDTH - (onRight ? PMONITOR->m_reservedArea.right() : PMONITOR->m_reservedArea.left())) : WIDTH, HEIGHT);
|
||||
nd.position = WORKAREA.pos() + Vector2D(nextX, nextY);
|
||||
applyNodeDataToWindow(&nd);
|
||||
|
||||
if (onRight) {
|
||||
|
|
@ -637,6 +636,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
||||
PHLMONITOR PMONITOR = nullptr;
|
||||
|
||||
const auto WS = g_pCompositor->getWorkspaceByID(pNode->workspaceID);
|
||||
|
||||
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
|
||||
for (auto const& m : g_pCompositor->m_monitors) {
|
||||
if (m->activeSpecialWorkspaceID() == pNode->workspaceID) {
|
||||
|
|
@ -644,19 +645,20 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
PMONITOR = g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_monitor.lock();
|
||||
} else if (WS)
|
||||
PMONITOR = WS->m_monitor.lock();
|
||||
|
||||
if (!PMONITOR) {
|
||||
if (!PMONITOR || !WS) {
|
||||
Debug::log(ERR, "Orphaned Node {}!!", pNode);
|
||||
return;
|
||||
}
|
||||
|
||||
// for gaps outer
|
||||
const bool DISPLAYLEFT = STICKS(pNode->position.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x);
|
||||
const bool DISPLAYRIGHT = STICKS(pNode->position.x + pNode->size.x, PMONITOR->m_position.x + PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x);
|
||||
const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->m_position.y + PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y);
|
||||
const auto WORKAREA = workAreaOnWorkspace(WS);
|
||||
const bool DISPLAYLEFT = STICKS(pNode->position.x, WORKAREA.x);
|
||||
const bool DISPLAYRIGHT = STICKS(pNode->position.x + pNode->size.x, WORKAREA.x + WORKAREA.w);
|
||||
const bool DISPLAYTOP = STICKS(pNode->position.y, WORKAREA.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, WORKAREA.y + WORKAREA.h);
|
||||
|
||||
const auto PWINDOW = pNode->pWindow.lock();
|
||||
// get specific gaps and rules for this workspace,
|
||||
|
|
@ -669,14 +671,11 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
|||
PWINDOW->m_ruleApplicator->resetProps(Desktop::Rule::RULE_PROP_ALL, Desktop::Types::PRIORITY_LAYOUT);
|
||||
PWINDOW->updateWindowData();
|
||||
|
||||
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
|
||||
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
|
||||
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
|
||||
auto* PGAPSIN = sc<CCssGapData*>((PGAPSINDATA.ptr())->getData());
|
||||
auto* PGAPSOUT = sc<CCssGapData*>((PGAPSOUTDATA.ptr())->getData());
|
||||
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
|
||||
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
|
||||
auto* PGAPSIN = sc<CCssGapData*>((PGAPSINDATA.ptr())->getData());
|
||||
|
||||
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
|
||||
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
|
||||
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
|
||||
|
||||
if (!validMapped(PWINDOW)) {
|
||||
Debug::log(ERR, "Node {} holding invalid {}!!", pNode, PWINDOW);
|
||||
|
|
@ -691,9 +690,9 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
|||
auto calcPos = PWINDOW->m_position;
|
||||
auto calcSize = PWINDOW->m_size;
|
||||
|
||||
const auto OFFSETTOPLEFT = Vector2D(sc<double>(DISPLAYLEFT ? gapsOut.m_left : gapsIn.m_left), sc<double>(DISPLAYTOP ? gapsOut.m_top : gapsIn.m_top));
|
||||
const auto OFFSETTOPLEFT = Vector2D(sc<double>(DISPLAYLEFT ? 0 : gapsIn.m_left), sc<double>(DISPLAYTOP ? 0 : gapsIn.m_top));
|
||||
|
||||
const auto OFFSETBOTTOMRIGHT = Vector2D(sc<double>(DISPLAYRIGHT ? gapsOut.m_right : gapsIn.m_right), sc<double>(DISPLAYBOTTOM ? gapsOut.m_bottom : gapsIn.m_bottom));
|
||||
const auto OFFSETBOTTOMRIGHT = Vector2D(sc<double>(DISPLAYRIGHT ? 0 : gapsIn.m_right), sc<double>(DISPLAYBOTTOM ? 0 : gapsIn.m_bottom));
|
||||
|
||||
calcPos = calcPos + OFFSETTOPLEFT;
|
||||
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
|
||||
|
|
@ -708,20 +707,17 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
|
|||
|
||||
if (*PCLAMP_TILED) {
|
||||
const auto borderSize = PWINDOW->getRealBorderSize();
|
||||
Vector2D monitorAvailable = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight -
|
||||
Vector2D{(double)(gapsOut.m_left + gapsOut.m_right), (double)(gapsOut.m_top + gapsOut.m_bottom)} - Vector2D{2.0 * borderSize, 2.0 * borderSize};
|
||||
Vector2D monitorAvailable = WORKAREA.size() - Vector2D{2.0 * borderSize, 2.0 * borderSize};
|
||||
|
||||
Vector2D minSize = PWINDOW->m_ruleApplicator->minSize().valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}).clamp(Vector2D{0, 0}, monitorAvailable);
|
||||
Vector2D maxSize = PWINDOW->isFullscreen() ? Vector2D{INFINITY, INFINITY} :
|
||||
PWINDOW->m_ruleApplicator->maxSize().valueOr(Vector2D{INFINITY, INFINITY}).clamp(Vector2D{0, 0}, monitorAvailable);
|
||||
calcSize = calcSize.clamp(minSize, maxSize);
|
||||
Vector2D minSize = PWINDOW->m_ruleApplicator->minSize().valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}).clamp(Vector2D{0, 0}, monitorAvailable);
|
||||
Vector2D maxSize = PWINDOW->isFullscreen() ? Vector2D{INFINITY, INFINITY} :
|
||||
PWINDOW->m_ruleApplicator->maxSize().valueOr(Vector2D{INFINITY, INFINITY}).clamp(Vector2D{0, 0}, monitorAvailable);
|
||||
calcSize = calcSize.clamp(minSize, maxSize);
|
||||
|
||||
calcPos += (availableSpace - calcSize) / 2.0;
|
||||
|
||||
calcPos.x = std::clamp(calcPos.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x + gapsOut.m_left + borderSize,
|
||||
PMONITOR->m_size.x + PMONITOR->m_position.x - PMONITOR->m_reservedBottomRight.x - gapsOut.m_right - calcSize.x - borderSize);
|
||||
calcPos.y = std::clamp(calcPos.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y + gapsOut.m_top + borderSize,
|
||||
PMONITOR->m_size.y + PMONITOR->m_position.y - PMONITOR->m_reservedBottomRight.y - gapsOut.m_bottom - calcSize.y - borderSize);
|
||||
calcPos.x = std::clamp(calcPos.x, WORKAREA.x + borderSize, WORKAREA.x + WORKAREA.w - calcSize.x - borderSize);
|
||||
calcPos.y = std::clamp(calcPos.y, WORKAREA.y + borderSize, WORKAREA.y + WORKAREA.h - calcSize.y - borderSize);
|
||||
}
|
||||
|
||||
if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) {
|
||||
|
|
@ -776,10 +772,11 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
|
|||
static auto SLAVECOUNTFORCENTER = CConfigValue<Hyprlang::INT>("master:slave_count_for_center_master");
|
||||
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing");
|
||||
|
||||
const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_position.y + PWINDOW->m_size.y, PMONITOR->m_position.y + PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y);
|
||||
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_position.x + PWINDOW->m_size.x, PMONITOR->m_position.x + PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x);
|
||||
const bool DISPLAYTOP = STICKS(PWINDOW->m_position.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y);
|
||||
const bool DISPLAYLEFT = STICKS(PWINDOW->m_position.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x);
|
||||
const auto WORKAREA = PMONITOR->logicalBoxMinusReserved();
|
||||
const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_position.y + PWINDOW->m_size.y, WORKAREA.y + WORKAREA.h);
|
||||
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_position.x + PWINDOW->m_size.x, WORKAREA.x + WORKAREA.w);
|
||||
const bool DISPLAYTOP = STICKS(PWINDOW->m_position.y, WORKAREA.y);
|
||||
const bool DISPLAYLEFT = STICKS(PWINDOW->m_position.x, WORKAREA.x);
|
||||
|
||||
const bool LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT;
|
||||
const bool TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT;
|
||||
|
|
@ -825,13 +822,12 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
|
|||
const bool isStackVertical = orientation == ORIENTATION_LEFT || orientation == ORIENTATION_RIGHT || orientation == ORIENTATION_CENTER;
|
||||
|
||||
const auto RESIZEDELTA = isStackVertical ? pixResize.y : pixResize.x;
|
||||
const auto WSSIZE = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight;
|
||||
|
||||
auto nodesInSameColumn = PNODE->isMaster ? MASTERS : STACKWINDOWS;
|
||||
if (orientation == ORIENTATION_CENTER && !PNODE->isMaster)
|
||||
nodesInSameColumn = DISPLAYRIGHT ? (nodesInSameColumn + 1) / 2 : nodesInSameColumn / 2;
|
||||
|
||||
const auto SIZE = isStackVertical ? WSSIZE.y / nodesInSameColumn : WSSIZE.x / nodesInSameColumn;
|
||||
const auto SIZE = isStackVertical ? WORKAREA.h / nodesInSameColumn : WORKAREA.w / nodesInSameColumn;
|
||||
|
||||
if (RESIZEDELTA != 0 && nodesInSameColumn > 1) {
|
||||
if (!*PSMARTRESIZING) {
|
||||
|
|
@ -840,7 +836,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
|
|||
const auto NODEIT = std::ranges::find(m_masterNodesData, *PNODE);
|
||||
const auto REVNODEIT = std::ranges::find(m_masterNodesData | std::views::reverse, *PNODE);
|
||||
|
||||
const float totalSize = isStackVertical ? WSSIZE.y : WSSIZE.x;
|
||||
const float totalSize = isStackVertical ? WORKAREA.h : WORKAREA.w;
|
||||
const float minSize = totalSize / nodesInSameColumn * 0.2;
|
||||
const bool resizePrevNodes = isStackVertical ? (TOP || DISPLAYBOTTOM) && !DISPLAYTOP : (LEFT || DISPLAYRIGHT) && !DISPLAYLEFT;
|
||||
|
||||
|
|
@ -936,9 +932,10 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFul
|
|||
// To keep consistent with the settings without C+P code
|
||||
|
||||
SMasterNodeData fakeNode;
|
||||
const auto WORKAREA = PMONITOR->logicalBoxMinusReserved();
|
||||
fakeNode.pWindow = pWindow;
|
||||
fakeNode.position = PMONITOR->m_position + PMONITOR->m_reservedTopLeft;
|
||||
fakeNode.size = PMONITOR->m_size - PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight;
|
||||
fakeNode.position = WORKAREA.pos();
|
||||
fakeNode.size = WORKAREA.size();
|
||||
fakeNode.workspaceID = pWindow->workspaceID();
|
||||
pWindow->m_position = fakeNode.position;
|
||||
pWindow->m_size = fakeNode.size;
|
||||
|
|
|
|||
|
|
@ -1156,11 +1156,7 @@ SDispatchResult CKeybindManager::centerWindow(std::string args) {
|
|||
|
||||
const auto PMONITOR = PWINDOW->m_monitor.lock();
|
||||
|
||||
auto RESERVEDOFFSET = Vector2D();
|
||||
if (args == "1")
|
||||
RESERVEDOFFSET = (PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight) / 2.f;
|
||||
|
||||
*PWINDOW->m_realPosition = PMONITOR->middle() - PWINDOW->m_realSize->goal() / 2.f + RESERVEDOFFSET;
|
||||
*PWINDOW->m_realPosition = PMONITOR->logicalBoxMinusReserved().middle() - PWINDOW->m_realSize->goal() / 2.f;
|
||||
PWINDOW->m_position = PWINDOW->m_realPosition->goal();
|
||||
|
||||
return {};
|
||||
|
|
@ -1670,15 +1666,15 @@ SDispatchResult CKeybindManager::moveActiveTo(std::string args) {
|
|||
PGAPSOUT = sc<CCssGapData*>(PGAPSOUTDATA.ptr()->getData());
|
||||
|
||||
switch (arg) {
|
||||
case 'l': vPosx = PMONITOR->m_reservedTopLeft.x + BORDERSIZE + PMONITOR->m_position.x + PGAPSOUT->m_left; break;
|
||||
case 'l': vPosx = PMONITOR->m_reservedArea.left() + BORDERSIZE + PMONITOR->m_position.x + PGAPSOUT->m_left; break;
|
||||
case 'r':
|
||||
vPosx = PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x - PLASTWINDOW->m_realSize->goal().x - BORDERSIZE + PMONITOR->m_position.x - PGAPSOUT->m_right;
|
||||
vPosx = PMONITOR->m_size.x - PMONITOR->m_reservedArea.right() - PLASTWINDOW->m_realSize->goal().x - BORDERSIZE + PMONITOR->m_position.x - PGAPSOUT->m_right;
|
||||
break;
|
||||
case 't':
|
||||
case 'u': vPosy = PMONITOR->m_reservedTopLeft.y + BORDERSIZE + PMONITOR->m_position.y + PGAPSOUT->m_top; break;
|
||||
case 'u': vPosy = PMONITOR->m_reservedArea.top() + BORDERSIZE + PMONITOR->m_position.y + PGAPSOUT->m_top; break;
|
||||
case 'b':
|
||||
case 'd':
|
||||
vPosy = PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y - PLASTWINDOW->m_realSize->goal().y - BORDERSIZE + PMONITOR->m_position.y - PGAPSOUT->m_bottom;
|
||||
vPosy = PMONITOR->m_size.y - PMONITOR->m_reservedArea.bottom() - PLASTWINDOW->m_realSize->goal().y - BORDERSIZE + PMONITOR->m_position.y - PGAPSOUT->m_bottom;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -408,10 +408,11 @@ void CDesktopAnimationManager::animationSlide(PHLWINDOW pWindow, std::string for
|
|||
const auto MIDPOINT = GOALPOS + GOALSIZE / 2.f;
|
||||
|
||||
// check sides it touches
|
||||
const bool DISPLAYLEFT = STICKS(pWindow->m_position.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x);
|
||||
const bool DISPLAYRIGHT = STICKS(pWindow->m_position.x + pWindow->m_size.x, PMONITOR->m_position.x + PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x);
|
||||
const bool DISPLAYTOP = STICKS(pWindow->m_position.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(pWindow->m_position.y + pWindow->m_size.y, PMONITOR->m_position.y + PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y);
|
||||
const auto MONITOR_WORKAREA = PMONITOR->logicalBoxMinusReserved();
|
||||
const bool DISPLAYLEFT = STICKS(pWindow->m_position.x, MONITOR_WORKAREA.x);
|
||||
const bool DISPLAYRIGHT = STICKS(pWindow->m_position.x + pWindow->m_size.x, MONITOR_WORKAREA.x + MONITOR_WORKAREA.w);
|
||||
const bool DISPLAYTOP = STICKS(pWindow->m_position.y, MONITOR_WORKAREA.y);
|
||||
const bool DISPLAYBOTTOM = STICKS(pWindow->m_position.y + pWindow->m_size.y, MONITOR_WORKAREA.y + MONITOR_WORKAREA.h);
|
||||
|
||||
if (DISPLAYBOTTOM && DISPLAYTOP) {
|
||||
if (DISPLAYLEFT && DISPLAYRIGHT) {
|
||||
|
|
|
|||
|
|
@ -1883,30 +1883,16 @@ void CHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vector<PHL
|
|||
}
|
||||
|
||||
void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitor);
|
||||
|
||||
static auto BAR_POSITION = CConfigValue<Hyprlang::INT>("debug:error_position");
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitor);
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
|
||||
// Reset the reserved
|
||||
PMONITOR->m_reservedBottomRight = Vector2D();
|
||||
PMONITOR->m_reservedTopLeft = Vector2D();
|
||||
PMONITOR->m_reservedArea.resetType(Desktop::RESERVED_DYNAMIC_TYPE_LS);
|
||||
|
||||
CBox usableArea = {PMONITOR->m_position.x, PMONITOR->m_position.y, PMONITOR->m_size.x, PMONITOR->m_size.y};
|
||||
|
||||
if (g_pHyprError->active() && Desktop::focusState()->monitor() == PMONITOR->m_self) {
|
||||
const auto HEIGHT = g_pHyprError->height();
|
||||
if (*BAR_POSITION == 0) {
|
||||
PMONITOR->m_reservedTopLeft.y = HEIGHT;
|
||||
usableArea.y += HEIGHT;
|
||||
usableArea.h -= HEIGHT;
|
||||
} else {
|
||||
PMONITOR->m_reservedBottomRight.y = HEIGHT;
|
||||
usableArea.h -= HEIGHT;
|
||||
}
|
||||
}
|
||||
const CBox ORIGINAL_USABLE_AREA = PMONITOR->logicalBoxMinusReserved();
|
||||
CBox usableArea = ORIGINAL_USABLE_AREA;
|
||||
|
||||
for (auto& la : PMONITOR->m_layerSurfaceLayers) {
|
||||
std::ranges::stable_sort(
|
||||
|
|
@ -1919,18 +1905,7 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) {
|
|||
for (auto const& la : PMONITOR->m_layerSurfaceLayers)
|
||||
arrangeLayerArray(PMONITOR, la, false, &usableArea);
|
||||
|
||||
PMONITOR->m_reservedTopLeft = Vector2D(usableArea.x, usableArea.y) - PMONITOR->m_position;
|
||||
PMONITOR->m_reservedBottomRight = PMONITOR->m_size - Vector2D(usableArea.width, usableArea.height) - PMONITOR->m_reservedTopLeft;
|
||||
|
||||
auto ADDITIONALRESERVED = g_pConfigManager->m_mAdditionalReservedAreas.find(PMONITOR->m_name);
|
||||
if (ADDITIONALRESERVED == g_pConfigManager->m_mAdditionalReservedAreas.end()) {
|
||||
ADDITIONALRESERVED = g_pConfigManager->m_mAdditionalReservedAreas.find(""); // glob wildcard
|
||||
}
|
||||
|
||||
if (ADDITIONALRESERVED != g_pConfigManager->m_mAdditionalReservedAreas.end()) {
|
||||
PMONITOR->m_reservedTopLeft = PMONITOR->m_reservedTopLeft + Vector2D(ADDITIONALRESERVED->second.left, ADDITIONALRESERVED->second.top);
|
||||
PMONITOR->m_reservedBottomRight = PMONITOR->m_reservedBottomRight + Vector2D(ADDITIONALRESERVED->second.right, ADDITIONALRESERVED->second.bottom);
|
||||
}
|
||||
PMONITOR->m_reservedArea.addType(Desktop::RESERVED_DYNAMIC_TYPE_LS, Desktop::CReservedArea{ORIGINAL_USABLE_AREA, usableArea});
|
||||
|
||||
// damage the monitor if can
|
||||
damageMonitor(PMONITOR);
|
||||
|
|
|
|||
38
tests/desktop/Reserved.cpp
Normal file
38
tests/desktop/Reserved.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
#include <desktop/reserved/ReservedArea.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(Desktop, reservedArea) {
|
||||
Desktop::CReservedArea a{{20, 30}, {40, 50}};
|
||||
CBox box = {1000, 1000, 1000, 1000};
|
||||
a.applyip(box);
|
||||
|
||||
EXPECT_EQ(box.x, 1020);
|
||||
EXPECT_EQ(box.y, 1030);
|
||||
EXPECT_EQ(box.w, 1000 - 20 - 40);
|
||||
EXPECT_EQ(box.h, 1000 - 30 - 50);
|
||||
|
||||
box = a.apply(CBox{1000, 1000, 1000, 1000});
|
||||
|
||||
EXPECT_EQ(box.x, 1020);
|
||||
EXPECT_EQ(box.y, 1030);
|
||||
EXPECT_EQ(box.w, 1000 - 20 - 40);
|
||||
EXPECT_EQ(box.h, 1000 - 30 - 50);
|
||||
|
||||
a.addType(Desktop::RESERVED_DYNAMIC_TYPE_LS, {10, 20}, {30, 40});
|
||||
|
||||
box = a.apply(CBox{1000, 1000, 1000, 1000});
|
||||
|
||||
EXPECT_EQ(box.x, 1000 + 20 + 10);
|
||||
EXPECT_EQ(box.y, 1000 + 30 + 20);
|
||||
EXPECT_EQ(box.w, 1000 - 20 - 40 - 10 - 30);
|
||||
EXPECT_EQ(box.h, 1000 - 30 - 50 - 20 - 40);
|
||||
|
||||
Desktop::CReservedArea b{CBox{10, 10, 1000, 1000}, CBox{20, 30, 900, 900}};
|
||||
|
||||
EXPECT_EQ(b.left(), 20 - 10);
|
||||
EXPECT_EQ(b.top(), 30 - 10);
|
||||
EXPECT_EQ(b.right(), 1010 - 920);
|
||||
EXPECT_EQ(b.bottom(), 1010 - 930);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue