From 3026846fbc4698403b08a3ad770bcc0f74eb8660 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sun, 19 May 2024 18:37:48 -0400 Subject: [PATCH 01/35] Add Config Flag to hyprctl systeminfo --- hyprctl/main.cpp | 2 ++ src/debug/HyprCtl.cpp | 8 ++++++++ src/debug/HyprCtl.hpp | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index e9d7583cc53..f534730b1e5 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -297,6 +297,8 @@ int main(int argc, char** argv) { fullArgs += "r"; } else if (ARGS[i] == "-a" && !fullArgs.contains("a")) { fullArgs += "a"; + } else if (ARGS[i] == "-c" && !fullArgs.contains("c")) { + fullArgs += "c"; } else if (ARGS[i] == "--batch") { fullRequest = "--batch "; } else if (ARGS[i] == "--instance" || ARGS[i] == "-i") { diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 5107153380c..e3fa7dc9efa 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -895,6 +895,12 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); } + if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { + result += "======Config-Start======"; + result += "Config: " + execAndGet("cat ~/.config/hypr/hyprland.conf") + "\n"; + result += "======Config-End========"; + } + return result; } @@ -1638,6 +1644,8 @@ std::string CHyprCtl::getReply(std::string request) { reloadAll = true; else if (c == 'a') m_sCurrentRequestParams.all = true; + else if (c == 'c') + m_sCurrentRequestParams.sysInfoConfig = true; } if (sepIndex < request.size()) diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index ebcb87cfcc1..6f0173dd018 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -18,6 +18,7 @@ class CHyprCtl { struct { bool all = false; + bool sysInfoConfig = false; } m_sCurrentRequestParams; private: @@ -26,4 +27,4 @@ class CHyprCtl { std::vector> m_vCommands; }; -inline std::unique_ptr g_pHyprCtl; \ No newline at end of file +inline std::unique_ptr g_pHyprCtl; From 5a432027f0da95485f8cf932a9d7f8a21b401d7a Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sun, 19 May 2024 18:53:26 -0400 Subject: [PATCH 02/35] Use configCurrentPath member. --- src/debug/HyprCtl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index e3fa7dc9efa..7285d82db4f 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -897,7 +897,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { result += "======Config-Start======"; - result += "Config: " + execAndGet("cat ~/.config/hypr/hyprland.conf") + "\n"; + result += "Config: " + execAndGet(std::string("cat " + g_pConfigManager->configCurrentPath).c_str()) + "\n"; result += "======Config-End========"; } From b1234c5c37f99224d5822b14a62c541c00b9f1fb Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sun, 19 May 2024 18:55:10 -0400 Subject: [PATCH 03/35] Add --config as an option. --- hyprctl/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index f534730b1e5..bdf354e7636 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -297,7 +297,7 @@ int main(int argc, char** argv) { fullArgs += "r"; } else if (ARGS[i] == "-a" && !fullArgs.contains("a")) { fullArgs += "a"; - } else if (ARGS[i] == "-c" && !fullArgs.contains("c")) { + } else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) { fullArgs += "c"; } else if (ARGS[i] == "--batch") { fullRequest = "--batch "; From 89220ed4445741b01147244bfb852e61149df378 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sun, 19 May 2024 18:57:06 -0400 Subject: [PATCH 04/35] Add line breaks --- src/debug/HyprCtl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 7285d82db4f..cbd7a679409 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -896,9 +896,9 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) } if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { - result += "======Config-Start======"; + result += "\n======Config-Start======\n"; result += "Config: " + execAndGet(std::string("cat " + g_pConfigManager->configCurrentPath).c_str()) + "\n"; - result += "======Config-End========"; + result += "\n======Config-End========\n"; } return result; From 22800ceefeb6b14e4d9f8f393035758f1211228f Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sun, 19 May 2024 19:18:09 -0400 Subject: [PATCH 05/35] Amend Bug Report Template. --- .github/ISSUE_TEMPLATE/bug.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 08a9ad9c479..ed6d3ce1ce8 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -12,8 +12,8 @@ body: - type: textarea id: ver attributes: - label: Hyprland Version - description: "Paste the output of `hyprctl systeminfo` here." + label: System Info and Version + description: "Paste the output of `hyprctl systeminfo -c` here. If you have configs outside of the main config shown here, please attach or paste them below." value: "
System/Version info @@ -25,6 +25,26 @@ body: ``` +
" + validations: + required: true + + - type: textarea + id: ver + attributes: + label: Config Info + description: "If you replace your config with https://github.com/hyprwm/Hyprland/blob/main/example/hyprland.conf can you reproduce this issue? If yes please let us know below. If not Please make sure to include ALL hyprland config files here. *Issues that do not follow this will be closed.*" + value: "
+ Config Info + + + ```sh + + + + ``` + +
" validations: required: true From 157efec3ff1cb4a8ad54cf207040105d925b65ce Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sun, 19 May 2024 19:24:28 -0400 Subject: [PATCH 06/35] Formatting Header. --- src/debug/HyprCtl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index 6f0173dd018..b48ea26a114 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -17,8 +17,8 @@ class CHyprCtl { int m_iSocketFD = -1; struct { - bool all = false; - bool sysInfoConfig = false; + bool all = false; + bool sysInfoConfig = false; } m_sCurrentRequestParams; private: From 0d02baaca3288b714e68f8f42b507dd076475af0 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sat, 18 May 2024 18:28:48 +0000 Subject: [PATCH 07/35] layout: Fix shrinking pseudotile windows. (#6143) --- src/layout/IHyprLayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index a31180e1135..ffd9ddeae87 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -523,7 +523,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { CBox wb = {pWindow->m_vRealPosition.goal() + (pWindow->m_vRealSize.goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize}; wb.round(); - if (DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) && + if (!(pWindow->m_bIsFloating && pWindow->m_bIsPseudotiled) && DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.value().y, pWindow->m_vLastFloatingSize.y, 10)) { wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}}; } From bd9796e0780bd6a14492158b3844c65b8f1e9380 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 18 May 2024 21:20:01 +0100 Subject: [PATCH 08/35] input: find surface pos correctly when mouse drag is active fixes #6144 --- src/managers/input/InputManager.cpp | 37 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index e05520f43f4..f4f97236769 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -222,26 +222,29 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // if we are holding a pointer button, // and we're not dnd-ing, don't refocus. Keep focus on last surface. if (!PROTO::data->dndActive() && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus && !m_bHardInput) { - foundSurface = g_pSeatManager->state.pointerFocus; - pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface); - if (pFoundLayerSurface) { - surfacePos = pFoundLayerSurface->position; + foundSurface = g_pSeatManager->state.pointerFocus; + + // IME popups aren't desktop-like elements + // TODO: make them. + CInputPopup* foundPopup = m_sIMERelay.popupFromSurface(foundSurface); + if (foundPopup) { + surfacePos = foundPopup->globalBox().pos(); m_bFocusHeldByButtons = true; m_bRefocusHeldByButtons = refocus; } else { - CInputPopup* foundPopup = m_sIMERelay.popupFromSurface(foundSurface); - if (foundPopup) { - surfacePos = foundPopup->globalBox().pos(); - m_bFocusHeldByButtons = true; - m_bRefocusHeldByButtons = refocus; - } else if (!g_pCompositor->m_pLastWindow.expired()) { - foundSurface = g_pSeatManager->state.pointerFocus; - pFoundWindow = g_pCompositor->m_pLastWindow.lock(); - - surfaceCoords = g_pCompositor->vectorToSurfaceLocal(mouseCoords, pFoundWindow, foundSurface); - m_bFocusHeldByButtons = true; - m_bRefocusHeldByButtons = refocus; - } + auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface); + + if (HLSurface) { + const auto BOX = HLSurface->getSurfaceBoxGlobal(); + + if (BOX) { + surfacePos = BOX->pos(); + pFoundLayerSurface = HLSurface->getLayer(); + pFoundWindow = HLSurface->getWindow(); + } else // reset foundSurface, find one normally + foundSurface = nullptr; + } else // reset foundSurface, find one normally + foundSurface = nullptr; } } From 77889d0ccebc98cb3f7b24dd94c58163a804922b Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 21 May 2024 14:50:33 +0200 Subject: [PATCH 09/35] xdg-shell: fixup positioner behavior with slide and resize if sliding and resizing, include the slide in the resize to avoid off-screen surfaces. fixes #6150 --- src/protocols/XDGShell.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 9777281f6b0..cbb93de90cc 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -550,6 +550,14 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa return test.translate(-parentCoord - constraint.pos()); } + // if flips fail, we will slide and remember. + // if the positioner is allowed to resize, then resize the slid thing. + CBox test = predictedBox; + + // for slide and resize, defines the padding around the edge for the positioned + // surface. + constexpr int EDGE_PADDING = 4; + if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y)) { // attempt to slide const bool slideX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X; @@ -563,17 +571,15 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w; const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h; - CBox test = predictedBox; - // TODO: this isn't truly conformant. if (leftEdgeOut && slideX) - test.x = constraint.x; + test.x = constraint.x + EDGE_PADDING; if (rightEdgeOut && slideX) - test.x = constraint.x + constraint.w - predictedBox.w; + test.x = constraint.x + constraint.w - predictedBox.w - EDGE_PADDING; if (topEdgeOut && slideY) - test.y = constraint.y; + test.y = constraint.y + EDGE_PADDING; if (bottomEdgeOut && slideY) - test.y = constraint.y + constraint.h - predictedBox.y; + test.y = constraint.y + constraint.h - predictedBox.y - EDGE_PADDING; success = test.copy().expand(-1).inside(constraint); @@ -590,21 +596,19 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w; const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h; - CBox test = predictedBox; - // TODO: this isn't truly conformant. if (leftEdgeOut && resizeX) { - test.w = test.x + test.w - constraint.x; - test.x = constraint.x; + test.w = test.x + test.w - constraint.x - EDGE_PADDING; + test.x = constraint.x + EDGE_PADDING; } if (rightEdgeOut && resizeX) - test.w = -(constraint.w + constraint.x - test.w - test.x); + test.w = -(constraint.w + constraint.x - test.w - test.x + EDGE_PADDING); if (topEdgeOut && resizeY) { - test.h = test.y + test.h - constraint.y; - test.y = constraint.y; + test.h = test.y + test.h - constraint.y - EDGE_PADDING; + test.y = constraint.y + EDGE_PADDING; } if (bottomEdgeOut && resizeY) - test.h = -(constraint.h + constraint.y - test.h - test.y); + test.h = -(constraint.h + constraint.y - test.h - test.y + EDGE_PADDING); success = test.copy().expand(-1).inside(constraint); @@ -614,7 +618,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa LOGM(WARN, "Compositor/client bug: xdg_positioner couldn't find a place"); - return predictedBox.translate(-parentCoord - constraint.pos()); + return test.translate(-parentCoord - constraint.pos()); } CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { From f71e1144033cd0bdf221a5adea83567102229528 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 20 May 2024 17:29:35 +0300 Subject: [PATCH 10/35] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index ca05387b5c6..eba1996a071 100644 --- a/flake.lock +++ b/flake.lock @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1715879663, - "narHash": "sha256-/DwglRvj4XF4ECdNtrCIbthleszAZBwOiXG5A6r0K/c=", + "lastModified": 1716058375, + "narHash": "sha256-CwjWoVnBZE5SBpRx9dgSQGCr4Goxyfcyv3zZbOhVqzk=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "f5181a068c1b06f2db51f6222e50a0c665a2b0c3", + "rev": "3afed4364790aebe0426077631af1e164a9650cc", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1715787315, - "narHash": "sha256-cYApT0NXJfqBkKcci7D9Kr4CBYZKOQKDYA23q8XNuWg=", + "lastModified": 1716137900, + "narHash": "sha256-sowPU+tLQv8GlqtVtsXioTKeaQvlMz/pefcdwg8MvfM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "33d1e753c82ffc557b4a585c77de43d4c922ebb5", + "rev": "6c0b7a92c30122196a761b440ac0d46d3d9954f1", "type": "github" }, "original": { @@ -152,11 +152,11 @@ ] }, "locked": { - "lastModified": 1715788457, - "narHash": "sha256-32HOkjSIyANphV0p5gIwP4ONU/CcinhwOyVFB+tL/d0=", + "lastModified": 1716290197, + "narHash": "sha256-1u9Exrc7yx9qtES2brDh7/DDZ8w8ap1nboIOAtCgeuM=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "af7c87a32f5d67eb2ada908a6a700f4e74831943", + "rev": "91e48d6acd8a5a611d26f925e51559ab743bc438", "type": "github" }, "original": { From 282a05550cfa3f903230d8b1a57944fa14b11b7d Mon Sep 17 00:00:00 2001 From: giskard Date: Thu, 16 May 2024 00:13:56 +0800 Subject: [PATCH 11/35] build: update meson, cmake setup - meson . fix run_command() check warning . drop lines for compatability, as it's already using c++23 - cmake . generate `compile_commands.json` by default . position independent build: __FILE__ --- CMakeLists.txt | 7 +++++-- meson.build | 21 ++++++--------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43927fbe16c..858502cc5fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ project(Hyprland set(HYPRLAND_VERSION ${VER}) set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) -configure_file(hyprland.pc.in hyprland.pc @ONLY) +configure_file(hyprland.pc.in hyprland.pc @ONLY) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") @@ -90,9 +90,12 @@ include_directories( "protocols/") set(CMAKE_CXX_STANDARD 23) add_compile_definitions(WLR_USE_UNSTABLE) -add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith) +add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value + -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith + -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE) +set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) message(STATUS "Checking deps...") diff --git a/meson.build b/meson.build index 9b278198a5b..b7b23470112 100644 --- a/meson.build +++ b/meson.build @@ -5,20 +5,9 @@ project('Hyprland', 'cpp', 'c', 'default_library=static', 'optimization=3', 'buildtype=release', - 'debug=false' - # 'cpp_std=c++23' # not yet supported by meson, as of version 0.63.0 - ]) - -# clang v14.0.6 uses C++2b instead of C++23, so we've gotta account for that -# replace the following with a project default option once meson gets support for C++23 -cpp_compiler = meson.get_compiler('cpp') -if cpp_compiler.has_argument('-std=c++23') - add_global_arguments('-std=c++23', language: 'cpp') -elif cpp_compiler.has_argument('-std=c++2b') - add_global_arguments('-std=c++2b', language: 'cpp') -else - error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') -endif + 'debug=false', + 'cpp_std=c++23', + ]) add_project_arguments( [ @@ -26,9 +15,11 @@ add_project_arguments( '-Wno-unused-value', '-Wno-missing-field-initializers', '-Wno-narrowing', + '-Wno-pointer-arith', ], language: 'cpp') +cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif @@ -65,7 +56,7 @@ if get_option('buildtype') == 'debug' add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp') endif -version_h = run_command('sh', '-c', 'scripts/generateVersion.sh') +version_h = run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) globber = run_command('find', 'src', '-name', '*.h*', check: true) headers = globber.stdout().strip().split('\n') From 1056ffc1470817e015446d3ba39ed4183986d884 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 21 May 2024 21:29:56 +0300 Subject: [PATCH 12/35] Revert "CMake: use add_custom_command for generating protocols (#6104)" Fixes https://github.com/hyprwm/Hyprland/issues/6115. --- CMakeLists.txt | 118 +++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 858502cc5fc..40e0f32ab64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,11 +113,9 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprwayland-scanner>=0.3.8 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) -find_package(hyprwayland-scanner 0.3.8 REQUIRED) - file(GLOB_RECURSE SRCFILES "src/*.cpp") set(TRACY_CPP_FILES "") @@ -221,48 +219,42 @@ target_link_libraries(Hyprland rt PkgConfig::deps) function(protocol protoPath protoName external) if (external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + execute_process( + COMMAND ${WaylandScanner} server-header ${protoPath} protocols/${protoName}-protocol.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + execute_process( + COMMAND ${WaylandScanner} private-code ${protoPath} protocols/${protoName}-protocol.c + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c) else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + execute_process( + COMMAND ${WaylandScanner} server-header ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + execute_process( + COMMAND ${WaylandScanner} private-code ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.c + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c) endif() - - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h - COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c - COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) - target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) endfunction() function(protocolNew protoPath protoName external) if (external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + execute_process( + COMMAND hyprwayland-scanner ${protoPath} ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + execute_process( + COMMAND hyprwayland-scanner ${WAYLAND_PROTOCOLS_DIR}/${protoPath} ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) endif() - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp - ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp - 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 PRIVATE protocols/${protoName}.hpp) endfunction() function(protocolWayland) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp - ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp + execute_process( COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) target_sources(Hyprland PRIVATE protocols/wayland.cpp) - target_sources(Hyprland PRIVATE protocols/wayland.hpp) endfunction() target_link_libraries(Hyprland @@ -280,37 +272,37 @@ protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.x protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) -protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) -protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) -protocolNew("protocols" "wlr-output-power-management-unstable-v1" true) -protocolNew("protocols" "virtual-keyboard-unstable-v1" true) -protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true) -protocolNew("protocols" "input-method-unstable-v2" true) -protocolNew("protocols" "wlr-output-management-unstable-v1" true) -protocolNew("protocols" "kde-server-decoration" true) -protocolNew("protocols" "wlr-data-control-unstable-v1" true) -protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true) -protocolNew("protocols" "wlr-layer-shell-unstable-v1" true) -protocolNew("staging/tearing-control" "tearing-control-v1" false) -protocolNew("staging/fractional-scale" "fractional-scale-v1" false) -protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false) -protocolNew("staging/cursor-shape" "cursor-shape-v1" false) -protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false) -protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false) -protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false) -protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false) -protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false) -protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false) -protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false) -protocolNew("unstable/text-input" "text-input-unstable-v3" false) -protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false) -protocolNew("staging/xdg-activation" "xdg-activation-v1" false) -protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false) -protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false) -protocolNew("stable/tablet" "tablet-v2" false) -protocolNew("stable/presentation-time" "presentation-time" false) -protocolNew("stable/xdg-shell" "xdg-shell" false) -protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) +protocolNew("protocols/wlr-gamma-control-unstable-v1.xml" "wlr-gamma-control-unstable-v1" true) +protocolNew("protocols/wlr-foreign-toplevel-management-unstable-v1.xml" "wlr-foreign-toplevel-management-unstable-v1" true) +protocolNew("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true) +protocolNew("protocols/virtual-keyboard-unstable-v1.xml" "virtual-keyboard-unstable-v1" true) +protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer-unstable-v1" true) +protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) +protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) +protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true) +protocolNew("protocols/wlr-data-control-unstable-v1.xml" "wlr-data-control-unstable-v1" true) +protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true) +protocolNew("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true) +protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) +protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false) +protocolNew("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false) +protocolNew("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false) +protocolNew("unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "idle-inhibit-unstable-v1" false) +protocolNew("unstable/relative-pointer/relative-pointer-unstable-v1.xml" "relative-pointer-unstable-v1" false) +protocolNew("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" "xdg-decoration-unstable-v1" false) +protocolNew("staging/alpha-modifier/alpha-modifier-v1.xml" "alpha-modifier-v1" false) +protocolNew("staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml" "ext-foreign-toplevel-list-v1" false) +protocolNew("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" "pointer-gestures-unstable-v1" false) +protocolNew("unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml" "keyboard-shortcuts-inhibit-unstable-v1" false) +protocolNew("unstable/text-input/text-input-unstable-v3.xml" "text-input-unstable-v3" false) +protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" false) +protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false) +protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false) +protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false) +protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) +protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false) +protocolNew("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) +protocolNew("unstable/primary-selection/primary-selection-unstable-v1.xml" "primary-selection-unstable-v1" false) protocolWayland() From f4696a6256791e47cc39d05539dc24f1b3c6472e Mon Sep 17 00:00:00 2001 From: giskard Date: Wed, 22 May 2024 16:09:36 +0800 Subject: [PATCH 13/35] renderer: render fonts with pango, add global `font_family` config option (#6138) --- src/config/ConfigManager.cpp | 5 +- src/debug/HyprDebugOverlay.cpp | 111 +++++++++--------- src/debug/HyprNotificationOverlay.cpp | 109 ++++++++--------- src/debug/HyprNotificationOverlay.hpp | 3 - src/hyprerror/HyprError.cpp | 25 +++- src/render/OpenGL.cpp | 37 ++++-- .../decorations/CHyprGroupBarDecoration.cpp | 7 +- 7 files changed, 159 insertions(+), 138 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 3dc36899d23..14a326bbe59 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -324,7 +324,8 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:disable_hyprland_logo", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_splash_rendering", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:col.splash", Hyprlang::INT{0x55ffffff}); - m_pConfig->addConfigValue("misc:splash_font_family", {"Sans"}); + m_pConfig->addConfigValue("misc:splash_font_family", {STRVAL_EMPTY}); + m_pConfig->addConfigValue("misc:font_family", {"Sans"}); m_pConfig->addConfigValue("misc:force_default_wallpaper", Hyprlang::INT{-1}); m_pConfig->addConfigValue("misc:vfr", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:vrr", Hyprlang::INT{0}); @@ -353,7 +354,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); - m_pConfig->addConfigValue("group:groupbar:font_family", {"Sans"}); + m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); m_pConfig->addConfigValue("group:groupbar:gradients", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:height", Hyprlang::INT{14}); diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 37ccc67ae91..6d3ec9072b5 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -1,4 +1,6 @@ +#include #include "HyprDebugOverlay.hpp" +#include "config/ConfigValue.hpp" #include "../Compositor.hpp" void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { @@ -47,11 +49,6 @@ int CHyprMonitorDebugOverlay::draw(int offset) { if (!m_pMonitor) return 0; - int yOffset = offset; - cairo_text_extents_t cairoExtents; - float maxX = 0; - std::string text = ""; - // get avg fps float avgFrametime = 0; float maxFrametime = 0; @@ -105,23 +102,49 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick; avgAnimMgrTick /= m_dLastAnimationTicks.size() == 0 ? 1 : m_dLastAnimationTicks.size(); - const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms - const float idealFPS = m_dLastFrametimes.size(); - - cairo_select_font_face(g_pDebugOverlay->m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - - cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10); + const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms + const float idealFPS = m_dLastFrametimes.size(); + + static auto fontFamily = CConfigValue("misc:font_family"); + PangoLayout* layoutText = pango_cairo_create_layout(g_pDebugOverlay->m_pCairo); + PangoFontDescription* pangoFD = pango_font_description_new(); + + pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); + pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + + float maxTextW = 0; + int fontSize = 0; + auto cr = g_pDebugOverlay->m_pCairo; + + auto showText = [cr, layoutText, pangoFD, &maxTextW, &fontSize](const char* text, int size) { + if (fontSize != size) { + pango_font_description_set_absolute_size(pangoFD, size * PANGO_SCALE); + pango_layout_set_font_description(layoutText, pangoFD); + fontSize = size; + } + + pango_layout_set_text(layoutText, text, -1); + pango_cairo_show_layout(cr, layoutText); + + int textW = 0, textH = 0; + pango_layout_get_size(layoutText, &textW, &textH); + textW /= PANGO_SCALE; + textH /= PANGO_SCALE; + if (textW > maxTextW) + maxTextW = textW; + + // move to next line + cairo_rel_move_to(cr, 0, fontSize + 1); + }; + + const int MARGIN_TOP = 8; + const int MARGIN_LEFT = 4; + cairo_move_to(cr, MARGIN_LEFT, MARGIN_TOP + offset); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f); - yOffset += 10; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); - text = m_pMonitor->szName; - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; - - cairo_set_font_size(g_pDebugOverlay->m_pCairo, 16); + std::string text; + showText(m_pMonitor->szName.c_str(), 10); if (FPS > idealFPS * 0.95f) cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 0.2f, 1.f, 0.2f, 1.f); @@ -130,57 +153,35 @@ int CHyprMonitorDebugOverlay::draw(int offset) { else cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 0.2f, 0.2f, 1.f); - yOffset += 17; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("{} FPS", (int)FPS); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 16); - cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f); - yOffset += 11; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 10); - yOffset += 11; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("Avg Rendertime: {:.2f}ms (var {:.2f}ms)", avgRenderTime, varRenderTime); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 10); - yOffset += 11; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("Avg Rendertime (No Overlay): {:.2f}ms (var {:.2f}ms)", avgRenderTimeNoOverlay, varRenderTimeNoOverlay); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 10); - yOffset += 11; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("Avg Anim Tick: {:.2f}ms (var {:.2f}ms) ({:.2f} TPS)", avgAnimMgrTick, varAnimMgrTick, 1.0 / (avgAnimMgrTick / 1000.0)); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 10); + + pango_font_description_free(pangoFD); + g_object_unref(layoutText); - yOffset += 11; + double posX = 0, posY = 0; + cairo_get_current_point(cr, &posX, &posY); g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); - m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset - 1, (int)maxX + 2, - yOffset - offset + 2}; + m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1, + (int)maxTextW + 2, posY - offset - MARGIN_TOP + 2}; g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); - return yOffset - offset; + return posY - offset; } void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) { diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 80c80601709..e1fc810b9cd 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -1,6 +1,20 @@ +#include +#include #include "HyprNotificationOverlay.hpp" #include "../Compositor.hpp" -#include +#include "../config/ConfigValue.hpp" + +inline auto iconBackendFromLayout(PangoLayout* layout) { + // preference: Nerd > FontAwesome > text + auto eIconBackendChecks = std::array{ICONS_BACKEND_NF, ICONS_BACKEND_FA}; + for (auto iconID : eIconBackendChecks) { + auto iconsText = std::accumulate(ICONS_ARRAY[iconID].begin(), ICONS_ARRAY[iconID].end(), std::string()); + pango_layout_set_text(layout, iconsText.c_str(), -1); + if (pango_layout_get_unknown_glyphs_count(layout) == 0) + return iconID; + } + return ICONS_BACKEND_NONE; +} CHyprNotificationOverlay::CHyprNotificationOverlay() { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { @@ -9,31 +23,6 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() { g_pHyprRenderer->damageBox(&m_bLastDamage); }); - - // check for the icon backend - std::string fonts = execAndGet("fc-list"); - std::string fontsLower = fonts; - std::transform(fontsLower.begin(), fontsLower.end(), fontsLower.begin(), [&](char& i) { return std::tolower(i); }); - - size_t index = 0; - - if (index = fontsLower.find("nerd"); index != std::string::npos) { - m_eIconBackend = ICONS_BACKEND_NF; - } else if (index = fontsLower.find("font awesome"); index != std::string::npos) { - m_eIconBackend = ICONS_BACKEND_FA; - } else if (index = fontsLower.find("fontawesome"); index != std::string::npos) { - m_eIconBackend = ICONS_BACKEND_FA; - } else { - return; - } - - const auto LASTNEWLINE = fonts.find_last_of('\n', index); - const auto COLON = fonts.find(':', LASTNEWLINE); - const auto COMMA = fonts.find(',', COLON); - const auto NEWLINE = fonts.find('\n', COLON); - const auto LASTCHAR = COMMA < NEWLINE ? COMMA : NEWLINE; - - m_szIconFontName = fonts.substr(COLON + 2, LASTCHAR - (COLON + 2)); } CHyprNotificationOverlay::~CHyprNotificationOverlay() { @@ -81,25 +70,24 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { float offsetY = 10; float maxWidth = 0; - const auto SCALE = pMonitor->scale; - + const auto SCALE = pMonitor->scale; const auto MONSIZE = pMonitor->vecTransformedSize; - cairo_text_extents_t cairoExtents; - int iconW = 0, iconH = 0; + static auto fontFamily = CConfigValue("misc:font_family"); - cairo_select_font_face(m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + PangoLayout* layout = pango_cairo_create_layout(m_pCairo); + PangoFontDescription* pangoFD = pango_font_description_new(); - const auto PBEZIER = g_pAnimationManager->getBezier("default"); + pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); + pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); - for (auto& notif : m_dNotifications) { - const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; - const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); + const auto iconBackendID = iconBackendFromLayout(layout); + const auto PBEZIER = g_pAnimationManager->getBezier("default"); - PangoLayout* pangoLayout = pango_cairo_create_layout(m_pCairo); - PangoFontDescription* pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str()); - pango_layout_set_font_description(pangoLayout, pangoFD); - cairo_set_font_size(m_pCairo, FONTSIZE); + for (auto& notif : m_dNotifications) { + const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; + const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); // first rect (bg, col) const float FIRSTRECTANIMP = @@ -122,31 +110,37 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { const float THIRDRECTPERC = notif->started.getMillis() / notif->timeMs; // get text size - cairo_text_extents(m_pCairo, notif->text.c_str(), &cairoExtents); - const auto ICON = ICONS_ARRAY[m_eIconBackend][notif->icon]; + const auto ICON = ICONS_ARRAY[iconBackendID][notif->icon]; const auto ICONCOLOR = ICONS_COLORS[notif->icon]; - pango_layout_set_text(pangoLayout, ICON.c_str(), -1); - pango_layout_set_font_description(pangoLayout, pangoFD); - pango_cairo_update_layout(m_pCairo, pangoLayout); - pango_layout_get_size(pangoLayout, &iconW, &iconH); + + int iconW = 0, iconH = 0; + pango_font_description_set_absolute_size(pangoFD, PANGO_SCALE * FONTSIZE * ICON_SCALE); + pango_layout_set_font_description(layout, pangoFD); + pango_layout_set_text(layout, ICON.c_str(), -1); + pango_layout_get_size(layout, &iconW, &iconH); iconW /= PANGO_SCALE; iconH /= PANGO_SCALE; - cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); + int textW = 0, textH = 0; + pango_font_description_set_absolute_size(pangoFD, PANGO_SCALE * FONTSIZE); + pango_layout_set_font_description(layout, pangoFD); + pango_layout_set_text(layout, notif->text.c_str(), -1); + pango_layout_get_size(layout, &textW, &textH); + textW /= PANGO_SCALE; + textH /= PANGO_SCALE; - const auto NOTIFSIZE = Vector2D{cairoExtents.width + 20 + iconW + 2 * ICONPADFORNOTIF, cairoExtents.height + 10}; + const auto NOTIFSIZE = Vector2D{textW + 20 + iconW + 2 * ICONPADFORNOTIF, textH + 10}; // draw rects + cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y); cairo_fill(m_pCairo); cairo_set_source_rgb(m_pCairo, 0.f, 0.f, 0.f); - cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y); cairo_fill(m_pCairo); cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); - cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2); cairo_fill(m_pCairo); @@ -164,26 +158,27 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { // draw icon cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f); - cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY + std::round((NOTIFSIZE.y - iconH - 4) / 2.0)); - pango_cairo_show_layout(m_pCairo, pangoLayout); + cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY - 2 + std::round((NOTIFSIZE.y - iconH) / 2.0)); + pango_layout_set_text(layout, ICON.c_str(), -1); + pango_cairo_show_layout(m_pCairo, layout); } // draw text - cairo_set_font_size(m_pCairo, FONTSIZE); cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f); - cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY + FONTSIZE + (FONTSIZE / 10.0)); - cairo_show_text(m_pCairo, notif->text.c_str()); + cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY - 2 + std::round((NOTIFSIZE.y - textH) / 2.0)); + pango_layout_set_text(layout, notif->text.c_str(), -1); + pango_cairo_show_layout(m_pCairo, layout); // adjust offset and move on offsetY += NOTIFSIZE.y + 10; if (maxWidth < NOTIFSIZE.x) maxWidth = NOTIFSIZE.x; - - pango_font_description_free(pangoFD); - g_object_unref(pangoLayout); } + pango_font_description_free(pangoFD); + g_object_unref(layout); + // cleanup notifs std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; }); diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index d086ada901f..5c978089189 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -59,9 +59,6 @@ class CHyprNotificationOverlay { Vector2D m_vecLastSize = Vector2D(-1, -1); CTexture m_tTexture; - - eIconBackend m_eIconBackend = ICONS_BACKEND_NONE; - std::string m_szIconFontName = "Sans"; }; inline std::unique_ptr g_pHyprNotificationOverlay; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index e7e2ff0d264..d147a6bbfaa 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -1,3 +1,4 @@ +#include #include "HyprError.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" @@ -94,12 +95,19 @@ void CHyprError::createQueued() { // draw the text with a common font const CColor textColor = m_cQueued.r + m_cQueued.g + m_cQueued.b < 0.2f ? CColor(1.0, 1.0, 1.0, 1.0) : CColor(0, 0, 0, 1.0); - - cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(CAIRO, FONTSIZE); cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a); - float yoffset = TOPBAR ? FONTSIZE : Y - PAD + FONTSIZE; + static auto fontFamily = CConfigValue("misc:font_family"); + PangoLayout* layoutText = pango_cairo_create_layout(CAIRO); + PangoFontDescription* pangoFD = pango_font_description_new(); + + pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); + pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE); + pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layoutText, pangoFD); + + float yoffset = TOPBAR ? 0 : Y - PAD; int renderedcnt = 0; while (!m_szQueued.empty() && renderedcnt < VISLINECOUNT) { std::string current = m_szQueued.substr(0, m_szQueued.find('\n')); @@ -108,17 +116,22 @@ void CHyprError::createQueued() { else m_szQueued = ""; cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1); - cairo_show_text(CAIRO, current.c_str()); + pango_layout_set_text(layoutText, current.c_str(), -1); + pango_cairo_show_layout(CAIRO, layoutText); yoffset += FONTSIZE + (FONTSIZE / 10.f); renderedcnt++; } if (VISLINECOUNT < LINECOUNT) { std::string moreString = std::format("({} more...)", LINECOUNT - VISLINECOUNT); cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1); - cairo_show_text(CAIRO, moreString.c_str()); + pango_layout_set_text(layoutText, moreString.c_str(), -1); + pango_cairo_show_layout(CAIRO, layoutText); } m_szQueued = ""; + pango_font_description_free(pangoFD); + g_object_unref(layoutText); + cairo_surface_flush(CAIROSURFACE); // copy the data to an OpenGL texture we have diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a8a20f30e1d..a1e6f73ef2f 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1,9 +1,9 @@ +#include +#include #include "Shaders.hpp" #include "OpenGL.hpp" #include "../Compositor.hpp" #include "../helpers/MiscFunctions.hpp" -#include "Shaders.hpp" -#include #include "../config/ConfigValue.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/LayerShell.hpp" @@ -2097,25 +2097,36 @@ void CHyprOpenGLImpl::renderMirrored() { } void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) { - static auto PSPLASHCOLOR = CConfigValue("misc:col.splash"); - - static auto PSPLASHFONT = CConfigValue("misc:splash_font_family"); + static auto PSPLASHCOLOR = CConfigValue("misc:col.splash"); + static auto PSPLASHFONT = CConfigValue("misc:splash_font_family"); + static auto FALLBACKFONT = CConfigValue("misc:font_family"); - cairo_select_font_face(CAIRO, (*PSPLASHFONT).c_str(), CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + const auto FONTFAMILY = *PSPLASHFONT != STRVAL_EMPTY ? *PSPLASHFONT : *FALLBACKFONT; + const auto FONTSIZE = (int)(size.y / 76); + const auto COLOR = CColor(*PSPLASHCOLOR); - const auto FONTSIZE = (int)(size.y / 76); - cairo_set_font_size(CAIRO, FONTSIZE); + PangoLayout* layoutText = pango_cairo_create_layout(CAIRO); + PangoFontDescription* pangoFD = pango_font_description_new(); - const auto COLOR = CColor(*PSPLASHCOLOR); + pango_font_description_set_family_static(pangoFD, FONTFAMILY.c_str()); + pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE); + pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layoutText, pangoFD); cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a); - cairo_text_extents_t textExtents; - cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents); + int textW = 0, textH = 0; + pango_layout_set_text(layoutText, g_pCompositor->m_szCurrentSplash.c_str(), -1); + pango_layout_get_size(layoutText, &textW, &textH); + textW /= PANGO_SCALE; + textH /= PANGO_SCALE; - cairo_move_to(CAIRO, (size.x - textExtents.width) / 2.0, size.y - textExtents.height + offsetY); + cairo_move_to(CAIRO, (size.x - textW) / 2.0, size.y - textH * 2 + offsetY); + pango_cairo_show_layout(CAIRO, layoutText); - cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str()); + pango_font_description_free(pangoFD); + g_object_unref(layoutText); cairo_surface_flush(CAIROSURFACE); } diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 318999eda02..04f69aaa3d1 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -209,11 +209,13 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y); const auto CAIRO = cairo_create(CAIROSURFACE); + static auto FALLBACKFONT = CConfigValue("misc:font_family"); static auto PTITLEFONTFAMILY = CConfigValue("group:groupbar:font_family"); static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); static auto PTEXTCOLOR = CConfigValue("group:groupbar:text_color"); - const CColor COLOR = CColor(*PTEXTCOLOR); + const CColor COLOR = CColor(*PTEXTCOLOR); + const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT; // clear the pixmap cairo_save(CAIRO); @@ -225,7 +227,8 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float PangoLayout* layout = pango_cairo_create_layout(CAIRO); pango_layout_set_text(layout, szContent.c_str(), -1); - PangoFontDescription* fontDesc = pango_font_description_from_string((*PTITLEFONTFAMILY).c_str()); + PangoFontDescription* fontDesc = pango_font_description_new(); + pango_font_description_set_family_static(fontDesc, FONTFAMILY.c_str()); pango_font_description_set_size(fontDesc, *PTITLEFONTSIZE * PANGO_SCALE * monitorScale); pango_layout_set_font_description(layout, fontDesc); pango_font_description_free(fontDesc); From 2de4a5f0e4899ce73ea1ed83666847cc0cb1815f Mon Sep 17 00:00:00 2001 From: shezdy <77217897+shezdy@users.noreply.github.com> Date: Wed, 22 May 2024 13:51:46 -0600 Subject: [PATCH 14/35] keybinds: Add option to disable window direction monitor fallback (#6182) * add monitor fallback option * format --- src/Compositor.cpp | 9 ++++++++- src/config/ConfigManager.cpp | 1 + src/managers/KeybindManager.cpp | 17 +++++++++++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index efbd997f2cb..5c9cfbade46 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1386,7 +1386,8 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { return nullptr; // 0 -> history, 1 -> shared length - static auto PMETHOD = CConfigValue("binds:focus_preferred_method"); + static auto PMETHOD = CConfigValue("binds:focus_preferred_method"); + static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); @@ -1416,6 +1417,9 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) continue; + if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) + continue; + const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y); @@ -1505,6 +1509,9 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) continue; + if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) + continue; + const auto DIST = w->middle().distance(pWindow->middle()); const auto ANGLE = vectorAngles(Vector2D{w->middle() - pWindow->middle()}, VECTORS.at(dir)); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 14a326bbe59..77aa2fb36c4 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -495,6 +495,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("binds:ignore_group_lock", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{1}); m_pConfig->addConfigValue("binds:disable_keybind_grabbing", Hyprlang::INT{0}); + m_pConfig->addConfigValue("binds:window_direction_monitor_fallback", Hyprlang::INT{1}); m_pConfig->addConfigValue("gestures:workspace_swipe", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_fingers", Hyprlang::INT{3}); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index ea06403122b..925a7fb74b3 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1220,8 +1220,9 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { } void CKeybindManager::moveFocusTo(std::string args) { - static auto PFULLCYCLE = CConfigValue("binds:movefocus_cycles_fullscreen"); - char arg = args[0]; + static auto PFULLCYCLE = CConfigValue("binds:movefocus_cycles_fullscreen"); + static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); + char arg = args[0]; if (!isDirection(args)) { Debug::log(ERR, "Cannot move focus in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); @@ -1230,7 +1231,9 @@ void CKeybindManager::moveFocusTo(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW) { - tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg)); + if (*PMONITORFALLBACK) + tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg)); + return; } @@ -1246,7 +1249,7 @@ void CKeybindManager::moveFocusTo(std::string args) { Debug::log(LOG, "No window found in direction {}, looking for a monitor", arg); - if (tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg))) + if (*PMONITORFALLBACK && tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg))) return; static auto PNOFALLBACK = CConfigValue("general:no_focus_fallback"); @@ -1317,6 +1320,8 @@ void CKeybindManager::moveActiveTo(std::string args) { moveActiveToWorkspaceSilent(PNEWMONITOR->activeWorkspace->getConfigName()); else moveActiveToWorkspace(PNEWMONITOR->activeWorkspace->getConfigName()); + + return; } if (!isDirection(args)) { @@ -1356,6 +1361,10 @@ void CKeybindManager::moveActiveTo(std::string args) { return; } + static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); + if (!*PMONITORFALLBACK) + return; + // Otherwise, we always want to move to the next monitor in that direction const auto PMONITORTOCHANGETO = g_pCompositor->getMonitorInDirection(arg); if (!PMONITORTOCHANGETO) From 3f4818f5c00408ef0b5b9f235cdda063e38c8eb1 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 22 May 2024 22:37:02 +0200 Subject: [PATCH 15/35] window: guard monitor in bounding box calculations fixes #6190 --- src/desktop/Window.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 56003ecaddb..7987c9d68a6 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -87,9 +87,9 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { const int BORDERSIZE = getRealBorderSize(); if (m_sAdditionalConfigData.dimAround) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); - return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, - {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; + if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) + return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, + {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; } SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; @@ -147,8 +147,8 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { CBox CWindow::getFullWindowBoundingBox() { if (m_sAdditionalConfigData.dimAround) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); - return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) + return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; } auto maxExtents = getFullWindowExtents(); From a17b98f436469b3af758927672b221b88f63ad8b Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 23 May 2024 00:42:16 +0200 Subject: [PATCH 16/35] screencopy: use a simple renderer for frame passing --- src/protocols/Screencopy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 7c25ed3f933..622d9d68fec 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -494,7 +494,7 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* CFramebuffer fb; fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat); - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb)) { + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { wlr_texture_destroy(sourceTex); wlr_buffer_end_data_ptr_access(frame->buffer); return false; @@ -557,7 +557,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer)) + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer, nullptr, true)) return false; CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} From 9739d09e324e52dd2dd4e91a8bf6272a98d785f9 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 22 May 2024 22:43:47 +0000 Subject: [PATCH 17/35] [gha] Nix: update inputs --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index eba1996a071..f285fe8fbb2 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1715791817, - "narHash": "sha256-J069Uhv/gCMFLX1dSh2f+9ZTM09r1Nv3oUfocCnWKow=", + "lastModified": 1716327911, + "narHash": "sha256-PI+wygItS/TKzi4gEAROvKTUzTx9GT+PGBttS/IOA/Q=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "7c3aa03dffb53921e583ade3d4ae3f487e390e7e", + "rev": "27ca640abeef2d425b5dbecf804f5eb622cef56d", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1716137900, - "narHash": "sha256-sowPU+tLQv8GlqtVtsXioTKeaQvlMz/pefcdwg8MvfM=", + "lastModified": 1716330097, + "narHash": "sha256-8BO3B7e3BiyIDsaKA0tY8O88rClYRTjvAp66y+VBUeU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6c0b7a92c30122196a761b440ac0d46d3d9954f1", + "rev": "5710852ba686cc1fd0d3b8e22b3117d43ba374c2", "type": "github" }, "original": { From 31209a41607ece377e823a69c2e8d8f59cfbe234 Mon Sep 17 00:00:00 2001 From: shezdy <77217897+shezdy@users.noreply.github.com> Date: Thu, 23 May 2024 05:01:12 -0600 Subject: [PATCH 18/35] internal: save previous workspace before change (#6202) --- src/managers/KeybindManager.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 925a7fb74b3..e23cb500899 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1071,6 +1071,14 @@ void CKeybindManager::changeworkspace(std::string args) { g_pCompositor->setActiveMonitor(PMONITORWORKSPACEOWNER); + if (BISWORKSPACECURRENT) { + if (*PALLOWWORKSPACECYCLES) + pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); + else if (!EXPLICITPREVIOUS && !*PBACKANDFORTH) + pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr); + } else + pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); + PMONITORWORKSPACEOWNER->changeWorkspace(pWorkspaceToChangeTo, false, true); if (PMONITOR != PMONITORWORKSPACEOWNER) { @@ -1083,14 +1091,6 @@ void CKeybindManager::changeworkspace(std::string args) { g_pCompositor->warpCursorTo(middle); } - if (BISWORKSPACECURRENT) { - if (*PALLOWWORKSPACECYCLES) - pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); - else if (!EXPLICITPREVIOUS && !*PBACKANDFORTH) - pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr); - } else - pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); - if (!g_pInputManager->m_bLastFocusOnLS) { if (g_pCompositor->m_pLastFocus) g_pInputManager->sendMotionEventsToFocused(); @@ -1163,13 +1163,13 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { else if (POLDWS->m_bIsSpecialWorkspace) g_pCompositor->getMonitorFromID(POLDWS->m_iMonitorID)->setSpecialWorkspace(nullptr); + if (*PALLOWWORKSPACECYCLES) + pWorkspace->rememberPrevWorkspace(POLDWS); + pMonitor->changeWorkspace(pWorkspace); g_pCompositor->focusWindow(PWINDOW); g_pCompositor->warpCursorTo(PWINDOW->middle()); - - if (*PALLOWWORKSPACECYCLES) - pWorkspace->rememberPrevWorkspace(POLDWS); } void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { From c67ddc030dc7b168e2d80c84a010e5c322454384 Mon Sep 17 00:00:00 2001 From: Ming-Chuan <10496191+sifmelcara@users.noreply.github.com> Date: Thu, 23 May 2024 04:52:32 -0700 Subject: [PATCH 19/35] tablet: fix mapping when mapped region is specified (#6206) When `region_size` is set in the config (non-empty `boundBox`), cursor is mapped to wrong coordinate because `CBox::translate` mutates `TAB->boundBox`, making all subsequent coordinate calculations wrong. This also fixes the edge case where user sets `region_position` but not `region_size`. --- src/managers/PointerManager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 4be91b806dc..ae17c6d6b54 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -696,8 +696,11 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { } } - if (!TAB->boundBox.empty()) - mappedArea = TAB->boundBox.translate(currentMonitor->vecPosition); + mappedArea.translate(TAB->boundBox.pos()); + if (!TAB->boundBox.empty()) { + mappedArea.w = TAB->boundBox.w; + mappedArea.h = TAB->boundBox.h; + } break; } case HID_TYPE_TOUCH: { From 143f8731015fe821e00b41c88510dd47357ba771 Mon Sep 17 00:00:00 2001 From: System64 <72354122+System64fumo@users.noreply.github.com> Date: Thu, 23 May 2024 19:04:39 +0300 Subject: [PATCH 20/35] debug: Add ARM GPU info (#6212) Added a simple way to get basic info about the GPU on ARM based systems --- src/debug/HyprCtl.cpp | 2 ++ src/helpers/MiscFunctions.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index cbd7a679409..a9821474ba4 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -883,6 +883,8 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) #if defined(__DragonFly__) || defined(__FreeBSD__) const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); +#elif defined(__arm__) || defined(__aarch64__) + const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); #else const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); #endif diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 7382d24c114..a520c9d432d 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -649,6 +649,8 @@ void logSystemInfo() { #if defined(__DragonFly__) || defined(__FreeBSD__) const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); +#elif defined(__arm__) || defined(__aarch64__) + const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); #else const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); #endif From 2c63c91a17647d03de927333b75755d871a7acdd Mon Sep 17 00:00:00 2001 From: Alessio Molinari Date: Thu, 23 May 2024 21:15:31 +0200 Subject: [PATCH 21/35] internal: Replace monitor rule when disabling head. (#6136) Closes #5978 --- src/config/ConfigManager.cpp | 12 ++++++++++++ src/config/ConfigManager.hpp | 1 + src/protocols/OutputManagement.cpp | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 77aa2fb36c4..fd70da7714b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1264,6 +1264,18 @@ void CConfigManager::appendMonitorRule(const SMonitorRule& r) { m_dMonitorRules.emplace_back(r); } +bool CConfigManager::replaceMonitorRule(const SMonitorRule& newrule) { + // Looks for an existing monitor rule (compared by name). + // If the rule exists, it is replaced with the input rule. + for (auto& r : m_dMonitorRules) { + if (r.name == newrule.name) { + r = newrule; + return true; + } + } + return false; +} + void CConfigManager::performMonitorReload() { bool overAgain = false; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 7fc132c6fa7..45b100eefba 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -128,6 +128,7 @@ class CConfigManager { void performMonitorReload(); void appendMonitorRule(const SMonitorRule&); + bool replaceMonitorRule(const SMonitorRule&); bool m_bWantsMonitorReload = false; bool m_bForceReload = false; bool m_bNoMonitorReload = false; diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index e77797262f3..68c50193650 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -106,6 +106,9 @@ COutputHead::COutputHead(SP resource_, CMonitor* pMonitor_) : } pMonitor = nullptr; + for (auto& m : PROTO::outputManagement->m_vManagers) { + m->sendDone(); + } }); listeners.monitorModeChange = pMonitor->events.modeChanged.registerListener([this](std::any d) { updateMode(); }); @@ -305,6 +308,8 @@ COutputConfiguration::COutputConfiguration(SP resour LOGM(LOG, "disableHead on {}", PMONITOR->szName); PMONITOR->activeMonitorRule.disabled = true; + if (!g_pConfigManager->replaceMonitorRule(PMONITOR->activeMonitorRule)) + g_pConfigManager->appendMonitorRule(PMONITOR->activeMonitorRule); g_pHyprRenderer->applyMonitorRule(PMONITOR, &PMONITOR->activeMonitorRule, false); }); @@ -356,6 +361,7 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { SMonitorRule newRule = PMONITOR->activeMonitorRule; newRule.name = PMONITOR->szName; + newRule.disabled = false; if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { newRule.resolution = {head->state.mode->getMode()->width, head->state.mode->getMode()->height}; @@ -380,7 +386,8 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { // reset properties for next set. head->committedProperties = 0; - g_pConfigManager->appendMonitorRule(newRule); + if (!g_pConfigManager->replaceMonitorRule(newRule)) + g_pConfigManager->appendMonitorRule(newRule); g_pConfigManager->m_bWantsMonitorReload = true; } From bd7b32be4907cead0c9bfee614bde16bb166fdf6 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 23 May 2024 21:19:14 +0200 Subject: [PATCH 22/35] pointermgr: ensure compositor exist on destroy (#6216) on exit of hyprland the CMonitor destroy signal comes after the compositor has been destructed, causing a heap use after free. add if check to ensure compositor exist and isnt shutting down when its triggered. --- src/managers/PointerManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index ae17c6d6b54..636eab1deb9 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -131,7 +131,11 @@ CPointerManager::CPointerManager() { PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); PMONITOR->events.destroy.registerStaticListener( - [this](void* owner, std::any data) { std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); }); }, nullptr); + [this](void* owner, std::any data) { + if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) + std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); }); + }, + nullptr); }); } From b465ad40ca445016f67f98ecd3764c4c63856309 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 24 May 2024 20:40:15 +0200 Subject: [PATCH 23/35] window: fix invalid env buffer size in getEnv --- src/desktop/Window.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7987c9d68a6..7a06aa6143c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1296,9 +1296,12 @@ std::unordered_map CWindow::getEnv() { needle += 512; } + if (needle <= 1) + return {}; + std::replace(buffer.begin(), buffer.end() - 1, '\0', '\n'); - CVarList envs(std::string{buffer.data(), needle - 1}, 0, '\n', true); + CVarList envs(std::string{buffer.data(), buffer.size() - 1}, 0, '\n', true); for (auto& e : envs) { if (!e.contains('=')) From 1fc8d6b5d1befec57919379d741311ac1de22dc0 Mon Sep 17 00:00:00 2001 From: thejch <66577496+thejch@users.noreply.github.com> Date: Fri, 24 May 2024 11:50:22 -0700 Subject: [PATCH 24/35] pointer: add back nvidia hardware cursor quirks (#6220) --- src/managers/PointerManager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 636eab1deb9..b199881e57d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -119,7 +119,17 @@ static bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_ } } - return output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888); + // Note: taken from https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4596/diffs#diff-content-e3ea164da86650995728d70bd118f6aa8c386797 + // If this fails to find a shared modifier try to use a linear + // modifier. This avoids a scenario where the hardware cannot render to + // linear textures but only linear textures are supported for cursors, + // as is the case with Nvidia and VmWare GPUs + if (!output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888)) { + // Clear the format as output_pick_format doesn't zero it + memset(format, 0, sizeof(*format)); + return output_pick_format(output, NULL, format, DRM_FORMAT_ARGB8888); + } + return true; } CPointerManager::CPointerManager() { From 272fb9c4455026a9c6409f1dc84ea7b55ed861ff Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 24 May 2024 20:56:42 +0200 Subject: [PATCH 25/35] monitor: avoid UB on undefined auto dir ref #6217 --- src/Compositor.cpp | 1 + src/helpers/Monitor.hpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5c9cfbade46..529a3b3dd4d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2666,6 +2666,7 @@ void CCompositor::arrangeMonitors() { maxXOffsetLeft = newPosition.x; break; case eAutoDirs::DIR_AUTO_RIGHT: + case eAutoDirs::DIR_AUTO_NONE: newPosition.x = maxXOffsetRight; maxXOffsetRight += m->vecSize.x; break; diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 7aa07a86736..e4456084d02 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -13,7 +13,8 @@ #include "signal/Signal.hpp" // Enum for the different types of auto directions, e.g. auto-left, auto-up. -enum class eAutoDirs { +enum eAutoDirs { + DIR_AUTO_NONE = 0, /* None will be treated as right. */ DIR_AUTO_UP, DIR_AUTO_DOWN, DIR_AUTO_LEFT, @@ -21,7 +22,7 @@ enum class eAutoDirs { }; struct SMonitorRule { - eAutoDirs autoDir; + eAutoDirs autoDir = DIR_AUTO_NONE; std::string name = ""; Vector2D resolution = Vector2D(1280, 720); Vector2D offset = Vector2D(0, 0); From 66da111c722414cf5ae2772483d3e7b6154d74db Mon Sep 17 00:00:00 2001 From: Can <45462997+yungcxn@users.noreply.github.com> Date: Fri, 24 May 2024 20:58:26 +0200 Subject: [PATCH 26/35] keybinds: Added new dispatcher (sendshortcut) (#6174) --- hyprctl/hyprctl.bash | 6 +- hyprctl/hyprctl.fish | 6 +- hyprctl/hyprctl.usage | 1 + hyprctl/hyprctl.zsh | 5 +- src/managers/KeybindManager.cpp | 154 +++++++++++++++++++++++++++- src/managers/KeybindManager.hpp | 7 ++ src/managers/input/InputManager.cpp | 4 +- 7 files changed, 174 insertions(+), 9 deletions(-) diff --git a/hyprctl/hyprctl.bash b/hyprctl/hyprctl.bash index 279ee518da8..0b4e6b861a2 100644 --- a/hyprctl/hyprctl.bash +++ b/hyprctl/hyprctl.bash @@ -23,12 +23,12 @@ _hyprctl () { local words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") + local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut") declare -A literal_transitions - literal_transitions[0]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [108]=5 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [96]=5 [97]=2 [27]=2 [28]=14 [100]=2 [102]=5)" + literal_transitions[0]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [108]=5 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [138]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [96]=5 [97]=2 [27]=2 [28]=14 [100]=2 [102]=5)" literal_transitions[3]="([72]=18 [13]=2 [32]=18 [54]=18 [55]=18 [89]=18 [104]=2 [120]=2 [76]=1 [16]=2 [123]=18 [3]=1 [5]=2 [63]=18 [127]=2 [129]=18 [80]=18 [130]=18 [83]=18 [31]=18 [48]=2 [12]=2 [85]=18 [10]=18 [86]=18 [137]=18)" - literal_transitions[7]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [97]=2 [27]=2 [28]=14 [100]=2)" + literal_transitions[7]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [138]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [97]=2 [27]=2 [28]=14 [100]=2)" literal_transitions[8]="([128]=2 [131]=2 [0]=2 [73]=2 [35]=2 [106]=2 [37]=2 [107]=2 [4]=2 [78]=2 [39]=2 [79]=2 [110]=2 [6]=2 [41]=2 [42]=2 [81]=2 [82]=2 [46]=2 [47]=2 [9]=2 [109]=2 [50]=2 [52]=2 [11]=2 [115]=2 [87]=2 [49]=2 [56]=2 [90]=2 [57]=2 [91]=2 [92]=2 [60]=2 [61]=2 [125]=2 [93]=2 [62]=2 [20]=2 [95]=2 [22]=2 [23]=2 [64]=2 [65]=2 [24]=2 [132]=2 [26]=2 [68]=2 [98]=2 [69]=2 [29]=2 [136]=2 [70]=2 [99]=2)" literal_transitions[9]="([114]=15 [111]=16)" literal_transitions[11]="([101]=2)" diff --git a/hyprctl/hyprctl.fish b/hyprctl/hyprctl.fish index 5d8d12cb336..6d31b25add6 100644 --- a/hyprctl/hyprctl.fish +++ b/hyprctl/hyprctl.fish @@ -29,7 +29,7 @@ function _hyprctl set COMP_CWORD (count $COMP_WORDS) end - set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" + set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut" set --local descriptions set descriptions[1] "Focus the next window on a workspace" @@ -130,12 +130,14 @@ function _hyprctl set descriptions[133] "Move the cursor to the corner of the active window" set descriptions[136] "INFO" set descriptions[137] "Resize a selected window" + set descriptions[138] "On shortcut X sends shortcut Y to a specified window" + set --local literal_transitions set literal_transitions[1] "set inputs 104 75 34 2 3 78 106 37 109 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 97 98 28 29 101 103; set tos 2 3 4 3 3 3 5 3 6 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 6 3 3 15 3 6" set literal_transitions[4] "set inputs 73 14 33 55 56 90 105 121 77 17 124 4 6 64 128 130 81 131 84 32 49 13 86 11 87 138; set tos 19 3 19 19 19 19 3 3 2 3 19 2 3 19 3 19 19 19 19 19 3 3 19 19 19 19" set literal_transitions[8] "set inputs 104 75 34 2 3 78 106 37 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 98 28 29 101; set tos 2 3 4 3 3 3 5 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3" - set literal_transitions[9] "set inputs 129 132 1 74 36 107 38 108 5 79 40 80 111 7 42 43 82 83 47 48 10 110 51 53 12 116 88 50 57 91 58 92 93 61 62 126 94 63 21 96 23 24 65 66 25 133 27 69 99 70 30 137 71 100; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" + set literal_transitions[9] "set inputs 129 132 1 74 36 107 38 108 5 79 40 80 111 7 42 43 82 83 47 48 10 110 51 53 12 116 88 50 57 91 58 92 93 61 62 126 94 63 21 96 23 24 65 66 25 133 27 69 99 70 30 137 71 100 138; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" set literal_transitions[10] "set inputs 115 112; set tos 16 17" set literal_transitions[12] "set inputs 102; set tos 3" set literal_transitions[14] "set inputs 22 117 31 136 119 44 72; set tos 2 2 2 2 2 2 2" diff --git a/hyprctl/hyprctl.usage b/hyprctl/hyprctl.usage index a98541ddcd8..8e75917ea07 100644 --- a/hyprctl/hyprctl.usage +++ b/hyprctl/hyprctl.usage @@ -94,6 +94,7 @@ hyprctl []... ::= (exec) "Execute a shell command" | (execr) "Execute a raw shell command" | (pass) "Pass the key to a specified window" + | (sendshortcut) "On shortcut X sends shortcut Y to a specified window" | (killactive) "Close the active window" | (closewindow) "Close a specified window" | (workspace) "Change the workspace" diff --git a/hyprctl/hyprctl.zsh b/hyprctl/hyprctl.zsh index 5e2a475b5f2..82276778135 100644 --- a/hyprctl/hyprctl.zsh +++ b/hyprctl/hyprctl.zsh @@ -17,7 +17,7 @@ _hyprctl_cmd_3 () { } _hyprctl () { - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") + local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut") local -A descriptions descriptions[1]="Focus the next window on a workspace" @@ -118,12 +118,13 @@ _hyprctl () { descriptions[133]="Move the cursor to the corner of the active window" descriptions[136]="INFO" descriptions[137]="Resize a selected window" + descriptions[138]="On shortcut X sends shortcut Y to a specified window" local -A literal_transitions literal_transitions[1]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [109]=6 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [97]=6 [98]=3 [28]=3 [29]=15 [101]=3 [103]=6)" literal_transitions[4]="([73]=19 [14]=3 [33]=19 [55]=19 [56]=19 [90]=19 [105]=3 [121]=3 [77]=2 [17]=3 [124]=19 [4]=2 [6]=3 [64]=19 [128]=3 [130]=19 [81]=19 [131]=19 [84]=19 [32]=19 [49]=3 [13]=3 [86]=19 [11]=19 [87]=19 [138]=19)" literal_transitions[8]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [98]=3 [28]=3 [29]=15 [101]=3)" - literal_transitions[9]="([129]=3 [132]=3 [1]=3 [74]=3 [36]=3 [107]=3 [38]=3 [108]=3 [5]=3 [79]=3 [40]=3 [80]=3 [111]=3 [7]=3 [42]=3 [43]=3 [82]=3 [83]=3 [47]=3 [48]=3 [10]=3 [110]=3 [51]=3 [53]=3 [12]=3 [116]=3 [88]=3 [50]=3 [57]=3 [91]=3 [58]=3 [92]=3 [93]=3 [61]=3 [62]=3 [126]=3 [94]=3 [63]=3 [21]=3 [96]=3 [23]=3 [24]=3 [65]=3 [66]=3 [25]=3 [133]=3 [27]=3 [69]=3 [99]=3 [70]=3 [30]=3 [137]=3 [71]=3 [100]=3)" + literal_transitions[9]="([129]=3 [132]=3 [1]=3 [74]=3 [36]=3 [107]=3 [38]=3 [108]=3 [5]=3 [79]=3 [40]=3 [80]=3 [111]=3 [7]=3 [42]=3 [43]=3 [82]=3 [83]=3 [47]=3 [48]=3 [10]=3 [110]=3 [51]=3 [53]=3 [12]=3 [116]=3 [88]=3 [50]=3 [57]=3 [91]=3 [58]=3 [92]=3 [93]=3 [61]=3 [62]=3 [126]=3 [94]=3 [63]=3 [21]=3 [96]=3 [23]=3 [24]=3 [65]=3 [66]=3 [25]=3 [133]=3 [27]=3 [69]=3 [99]=3 [70]=3 [30]=3 [137]=3 [71]=3 [100]=3 [138]=3)" literal_transitions[10]="([115]=16 [112]=17)" literal_transitions[12]="([102]=3)" literal_transitions[14]="([22]=2 [117]=2 [31]=2 [136]=2 [119]=2 [44]=2 [72]=2)" diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index e23cb500899..41b82d1092c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -89,6 +89,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["focuswindow"] = focusWindow; m_mDispatchers["submap"] = setSubmap; m_mDispatchers["pass"] = pass; + m_mDispatchers["sendshortcut"] = sendshortcut; m_mDispatchers["layoutmsg"] = layoutmsg; m_mDispatchers["toggleopaque"] = toggleOpaque; m_mDispatchers["dpms"] = dpms; @@ -589,7 +590,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi } for (auto& k : m_lKeybinds) { - const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "mouse"; + const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse"; const bool SPECIALTRIGGERED = std::find_if(m_vPressedSpecialBinds.begin(), m_vPressedSpecialBinds.end(), [&](const auto& other) { return other == &k; }) != m_vPressedSpecialBinds.end(); const bool IGNORECONDITIONS = @@ -2022,6 +2023,157 @@ void CKeybindManager::pass(std::string regexp) { g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), SL); } +void CKeybindManager::sendshortcut(std::string args) { + // args=[,WINDOW_RULES] + const auto ARGS = CVarList(args, 3); + if (ARGS.size() != 3) { + Debug::log(ERR, "sendshortcut: invalid args"); + return; + } + + const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]); + const auto KEY = ARGS[1]; + uint32_t keycode = 0; + bool isMouse = 0; + + // similar to parseKey in ConfigManager + if (isNumber(KEY) && std::stoi(KEY) > 9) + keycode = std::stoi(KEY); + else if (KEY.compare(0, 5, "code:") == 0 && isNumber(KEY.substr(5))) + keycode = std::stoi(KEY.substr(5)); + else if (KEY.compare(0, 6, "mouse:") == 0 && isNumber(KEY.substr(6))) { + keycode = std::stoi(KEY.substr(6)); + isMouse = 1; + if (keycode < 272) { + Debug::log(ERR, "sendshortcut: invalid mouse button"); + return; + } + } else { + + // here, we need to find the keycode from the key name + // this is not possible through xkb's lib, so we need to iterate through all keycodes + // once found, we save it to the cache + + const auto KEYSYM = xkb_keysym_from_name(KEY.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + keycode = 0; + + const auto KB = g_pSeatManager->keyboard; + + if (!KB) { + Debug::log(ERR, "sendshortcut: no kb"); + return; + } + + const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY); + + if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) { + xkb_keymap* km = KB->wlr()->keymap; + xkb_state* ks = KB->xkbTranslationState; + + xkb_keycode_t keycode_min, keycode_max; + keycode_min = xkb_keymap_min_keycode(km); + keycode_max = xkb_keymap_max_keycode(km); + + for (xkb_keycode_t kc = keycode_min; kc <= keycode_max; ++kc) { + xkb_keysym_t sym = xkb_state_key_get_one_sym(ks, kc); + + if (sym == KEYSYM) { + keycode = kc; + g_pKeybindManager->m_mKeyToCodeCache[KEYPAIRSTRING] = keycode; + } + } + + if (!keycode) { + Debug::log(ERR, "sendshortcut: key not found"); + return; + } + + } else + keycode = g_pKeybindManager->m_mKeyToCodeCache[KEYPAIRSTRING]; + } + + if (!keycode) { + Debug::log(ERR, "sendshortcut: invalid key"); + return; + } + + const std::string regexp = ARGS[2]; + PHLWINDOW PWINDOW = nullptr; + const auto LASTSURFACE = g_pCompositor->m_pLastFocus; + + //if regexp is not empty, send shortcut to current window + //else, dont change focus + if (regexp != "") { + PWINDOW = g_pCompositor->getWindowByRegex(regexp); + + if (!PWINDOW) { + Debug::log(ERR, "sendshortcut: window not found"); + return; + } + + if (!g_pSeatManager->keyboard) { + Debug::log(ERR, "No kb in sendshortcut?"); + return; + } + + if (!isMouse) + g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface.wlr()); + else + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), {1, 1}); + } + + //copied the rest from pass and modified it + // if wl -> xwl, activate destination + if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsX11) + g_pXWaylandManager->activateSurface(PWINDOW->m_pWLSurface.wlr(), true); + // if xwl -> xwl, send to current. Timing issues make this not work. + if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11) + PWINDOW = nullptr; + + g_pSeatManager->sendKeyboardMods(MOD, 0, 0, 0); + + if (g_pKeybindManager->m_iPassPressed == 1) { + if (!isMouse) + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_PRESSED); + else + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_PRESSED); + } else if (g_pKeybindManager->m_iPassPressed == 0) { + if (!isMouse) + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_RELEASED); + else + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_RELEASED); + } else { + // dynamic call of the dispatcher + if (!isMouse) { + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_PRESSED); + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_RELEASED); + } else { + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_PRESSED); + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_RELEASED); + } + } + + if (!PWINDOW) + return; + + if (PWINDOW->m_bIsX11) { //xwayland hack, see pass + if (!isMouse) { + g_pSeatManager->state.keyboardFocus = nullptr; + g_pSeatManager->state.keyboardFocusResource.reset(); + } else { + g_pSeatManager->state.pointerFocus = nullptr; + g_pSeatManager->state.pointerFocusResource.reset(); + } + } + + const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal(); + + if (!isMouse) + g_pSeatManager->setKeyboardFocus(LASTSURFACE); + else + g_pSeatManager->setPointerFocus(LASTSURFACE, SL); +} + void CKeybindManager::layoutmsg(std::string msg) { SLayoutMessageHeader hd = {g_pCompositor->m_pLastWindow.lock()}; g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index a2025bb012e..a5499987283 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -95,6 +95,12 @@ class CKeybindManager { std::list m_lKeybinds; + //since we cant find keycode through keyname in xkb: + //on sendshortcut call, we once search for keyname (e.g. "g") the correct keycode (e.g. 42) + //and cache it in this map to make sendshortcut calls faster + //we also store the keyboard pointer (in the string) to differentiate between different keyboard (layouts) + std::unordered_map m_mKeyToCodeCache; + private: std::deque m_dPressedKeys; @@ -177,6 +183,7 @@ class CKeybindManager { static void focusWindow(std::string); static void setSubmap(std::string); static void pass(std::string); + static void sendshortcut(std::string); static void layoutmsg(std::string); static void toggleOpaque(std::string); static void dpms(std::string); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index f4f97236769..52927d952f2 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -842,8 +842,10 @@ void CInputManager::setupKeyboard(SP keeb) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); const auto LAYOUT = PKEEB->getActiveLayout(); - if (PKEEB == g_pSeatManager->keyboard) + if (PKEEB == g_pSeatManager->keyboard) { g_pSeatManager->updateActiveKeyboardData(); + g_pKeybindManager->m_mKeyToCodeCache.clear(); + } g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEEB->hlName + "," + LAYOUT}); EMIT_HOOK_EVENT("activeLayout", (std::vector{PKEEB, LAYOUT})); From f2856604c5a5ee31ff78446c67862e58c1090458 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 24 May 2024 23:51:08 +0300 Subject: [PATCH 27/35] flake.lock: update --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index f285fe8fbb2..8fc80b1dcf8 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1716327911, - "narHash": "sha256-PI+wygItS/TKzi4gEAROvKTUzTx9GT+PGBttS/IOA/Q=", + "lastModified": 1716576411, + "narHash": "sha256-FIN1wMoyePBTtibCbaeJaoKNLuAYIGwLCWAYC1DJanw=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "27ca640abeef2d425b5dbecf804f5eb622cef56d", + "rev": "57298fc4f13c807e50ada2c986a3114b7fc2e621", "type": "github" }, "original": { @@ -61,11 +61,11 @@ ] }, "locked": { - "lastModified": 1715791527, - "narHash": "sha256-HhQ4zvGHrRjR63ltySSeg+x+0jb0lepiutWdnFhLRoo=", + "lastModified": 1716473782, + "narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "969cb076e5b76f2e823aeca1937a3e1f159812ee", + "rev": "87d5d984109c839482b88b4795db073eb9ed446f", "type": "github" }, "original": { From d67e3cfaa09d6e067a29056221533a90ea1235e4 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Fri, 24 May 2024 21:56:19 -0400 Subject: [PATCH 28/35] Move logging to a function. --- src/config/ConfigManager.cpp | 20 ++++++++++++++++++++ src/config/ConfigManager.hpp | 1 + src/debug/HyprCtl.cpp | 11 ++++++----- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fd70da7714b..a435e31fa73 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -633,6 +633,26 @@ std::string CConfigManager::getMainConfigPath() { return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf"); } +const std::string CConfigManager::getConfigString() { + std::string configString; + std::string line; + + for (auto path : this->configPaths) { + std::ifstream configFile(path.c_str()); + configString += ("\n\nConfig File: " + path + ": "); + if (!configFile.is_open()) { + Debug::log(LOG, "Config file not readable/found!"); + configString += "Read Failed\n"; + continue; + } + configString += "Read Succeeded\n"; + while (std::getline(configFile, line)) { + configString.append(line); + } + } + return configString; +} + std::string CConfigManager::getErrors() { return m_szConfigErrors; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 45b100eefba..ca22904d968 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -103,6 +103,7 @@ class CConfigManager { void onPluginLoadUnload(const std::string& name, bool load); static std::string getConfigDir(); static std::string getMainConfigPath(); + const std::string getConfigString(); SMonitorRule getMonitorRuleFor(const CMonitor&); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a9821474ba4..4ec0ee2b26d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -23,6 +23,7 @@ #include "../devices/IKeyboard.hpp" #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" +#include "config/ConfigManager.hpp" static void trimTrailingComma(std::string& str) { if (!str.empty() && str.back() == ',') @@ -897,11 +898,11 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); } - if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { - result += "\n======Config-Start======\n"; - result += "Config: " + execAndGet(std::string("cat " + g_pConfigManager->configCurrentPath).c_str()) + "\n"; - result += "\n======Config-End========\n"; - } + if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { + result += "\n======Config-Start======\n"; + result += g_pConfigManager->getConfigString(); + result += "\n======Config-End========\n"; + } return result; } From afc27632191787d74a793723c9f26008a3016d4b Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Fri, 24 May 2024 22:00:54 -0400 Subject: [PATCH 29/35] Format --- src/config/ConfigManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index a435e31fa73..790bb39b057 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -639,13 +639,13 @@ const std::string CConfigManager::getConfigString() { for (auto path : this->configPaths) { std::ifstream configFile(path.c_str()); - configString += ("\n\nConfig File: " + path + ": "); + configString += ("\n\nConfig File: " + path + ": "); if (!configFile.is_open()) { Debug::log(LOG, "Config file not readable/found!"); - configString += "Read Failed\n"; + configString += "Read Failed\n"; continue; } - configString += "Read Succeeded\n"; + configString += "Read Succeeded\n"; while (std::getline(configFile, line)) { configString.append(line); } From ea653249e9096d180e344d79cbc98f5f5fb4279e Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Fri, 24 May 2024 22:01:19 -0400 Subject: [PATCH 30/35] Format --- src/debug/HyprCtl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 4ec0ee2b26d..1faea41c1f6 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -898,11 +898,11 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); } - if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { - result += "\n======Config-Start======\n"; - result += g_pConfigManager->getConfigString(); - result += "\n======Config-End========\n"; - } + if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { + result += "\n======Config-Start======\n"; + result += g_pConfigManager->getConfigString(); + result += "\n======Config-End========\n"; + } return result; } From 1288159320e7ef24f78305761245565c5b713159 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sat, 25 May 2024 00:34:38 -0400 Subject: [PATCH 31/35] Add linebreak. --- src/config/ConfigManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 790bb39b057..891de6a1c59 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -647,7 +647,7 @@ const std::string CConfigManager::getConfigString() { } configString += "Read Succeeded\n"; while (std::getline(configFile, line)) { - configString.append(line); + configString.append(line + "\n"); } } return configString; From c4358fefaac6e8fbc7b1d2f8cfc02d816241f1c0 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sat, 25 May 2024 14:45:19 -0400 Subject: [PATCH 32/35] Read whole file instead of one line at a time. --- src/config/ConfigManager.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 891de6a1c59..8a13634d329 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -635,7 +635,7 @@ std::string CConfigManager::getMainConfigPath() { const std::string CConfigManager::getConfigString() { std::string configString; - std::string line; + std::string currFileContent; for (auto path : this->configPaths) { std::ifstream configFile(path.c_str()); @@ -646,9 +646,8 @@ const std::string CConfigManager::getConfigString() { continue; } configString += "Read Succeeded\n"; - while (std::getline(configFile, line)) { - configString.append(line + "\n"); - } + currFileContent.assign(std::istreambuf_iterator(configFile), std::istreambuf_iterator()); + configString.append(currFileContent); } return configString; } From 64a9035e451fbf9d0d604644bd80bb77bbb1a68d Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sat, 25 May 2024 14:46:35 -0400 Subject: [PATCH 33/35] Remove redundant c_str() --- src/config/ConfigManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 8a13634d329..b6f5b0b9596 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -638,7 +638,7 @@ const std::string CConfigManager::getConfigString() { std::string currFileContent; for (auto path : this->configPaths) { - std::ifstream configFile(path.c_str()); + std::ifstream configFile(path); configString += ("\n\nConfig File: " + path + ": "); if (!configFile.is_open()) { Debug::log(LOG, "Config file not readable/found!"); From dff12087540301f29ad54b51610769555ea19cf9 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sat, 25 May 2024 14:47:39 -0400 Subject: [PATCH 34/35] Remove redundant this-> --- src/config/ConfigManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b6f5b0b9596..f65b5abbbeb 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -637,7 +637,7 @@ const std::string CConfigManager::getConfigString() { std::string configString; std::string currFileContent; - for (auto path : this->configPaths) { + for (auto path : configPaths) { std::ifstream configFile(path); configString += ("\n\nConfig File: " + path + ": "); if (!configFile.is_open()) { From 77e59caca8fabb5043e777202163a5cbc0cdcfb2 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sat, 25 May 2024 14:57:34 -0400 Subject: [PATCH 35/35] Address feedback on issue template. --- .github/ISSUE_TEMPLATE/bug.yml | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index ed6d3ce1ce8..66ce5fa9578 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -13,7 +13,11 @@ body: id: ver attributes: label: System Info and Version - description: "Paste the output of `hyprctl systeminfo -c` here. If you have configs outside of the main config shown here, please attach or paste them below." + description: | + Paste the output of `hyprctl systeminfo -c` here (If you are on a + version that shows you help menu, omit the `-c` and attach config files + to the issue). If you have configs outside of the main config shown + here, please attach. value: "
System/Version info @@ -25,26 +29,6 @@ body: ``` -
" - validations: - required: true - - - type: textarea - id: ver - attributes: - label: Config Info - description: "If you replace your config with https://github.com/hyprwm/Hyprland/blob/main/example/hyprland.conf can you reproduce this issue? If yes please let us know below. If not Please make sure to include ALL hyprland config files here. *Issues that do not follow this will be closed.*" - value: "
- Config Info - - - ```sh - - - - ``` - -
" validations: required: true