diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..cb32972f --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,38 @@ +name: Release artifacts + +on: + release: + types: [published] + workflow_dispatch: + +jobs: + source-tarball: + runs-on: ubuntu-latest + steps: + - name: Checkout Hyprland + id: checkout + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Create tarball with submodules + id: tar + run: tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz * + + - id: whatrelease + name: Get latest release + uses: pozetroninc/github-action-get-latest-release@master + with: + owner: hyprwm + repo: Hyprland + excludes: prerelease, draft + + - name: Upload to release + id: upload + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: source.tar.gz + asset_name: source-${{ steps.whatrelease.outputs.release }}.tar.gz + tag: ${{ steps.whatrelease.outputs.release }} + overwrite: true diff --git a/.gitignore b/.gitignore index c5ae0678..27b80f06 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ _deps build/ result /.vscode/ +.envrc +.cache *.o *-protocol.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 90a23020..06aabd2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,12 +37,12 @@ execute_process( include_directories(. PRIVATE "subprojects/wlroots/include/") include_directories(. PRIVATE "subprojects/wlroots/build/include/") -add_compile_options(-std=c++20 -DWLR_USE_UNSTABLE ) +add_compile_options(-std=c++23 -DWLR_USE_UNSTABLE ) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing) find_package(Threads REQUIRED) find_package(PkgConfig REQUIRED) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo libdrm egl xkbcommon wlroots libinput xcb) +pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo libdrm egl xkbcommon libinput xcb) # we do not check for wlroots, as we provide it ourselves file(GLOB_RECURSE SRCFILES "src/*.cpp") @@ -80,7 +80,7 @@ include(CPack) target_link_libraries(Hyprland PkgConfig::deps) target_link_libraries(Hyprland - wlroots + ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.11032 # wlroots is provided by us pixman-1 OpenGL GLESv2 diff --git a/Makefile b/Makefile index 227d340f..99ac1324 100644 --- a/Makefile +++ b/Makefile @@ -107,11 +107,13 @@ all: cd ./hyprctl && make all && cd .. install: - [ ! -d /usr/include/wlr ] || mv /usr/include/wlr /usr/include/wlrBackup - [ ! -f /usr/lib/libwlroots.so ] || mv /usr/lib/libwlroots.so /usr/lib/libwlroots.so.backup - [ ! -f /usr/lib/pkgconfig/wlroots.pc ] || mv /usr/lib/pkgconfig/wlroots.pc /usr/lib/pkgconfig/wlroots.pc.backup + make clear + make fixwlr + cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../.. + make protocols + make release + cd hyprctl && make all && cd .. - make all mkdir -p ${PREFIX}/share/wayland-sessions cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions/ mkdir -p ${PREFIX}/bin @@ -122,17 +124,12 @@ install: cp ./assets/wall_4K.png ${PREFIX}/share/hyprland cp ./assets/wall_8K.png ${PREFIX}/share/hyprland - rm -rf /usr/include/wlr - rm -f /usr/lib/libwlroots.so - rm -f /usr/lib/pkgconfig/wlroots.pc - [ ! -d /usr/include/wlrBackup ] || mv /usr/include/wlrBackup /usr/include/wlr - [ ! -f /usr/lib/libwlroots.so.backup ] || mv -f /usr/lib/libwlroots.so.backup /usr/lib/libwlroots.so - [ ! -f /usr/lib/pkgconfig/wlroots.pc.backup ] || mv -f /usr/lib/pkgconfig/wlroots.pc.backup /usr/lib/pkgconfig/wlroots.pc uninstall: rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop rm -f ${PREFIX}/bin/Hyprland rm -f ${PREFIX}/bin/hyprctl + rm -f /usr/lib/libwlroots.so.11032 rm -rf ${PREFIX}/share/hyprland protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o diff --git a/README.md b/README.md index 3f182556..6f081861 100644 --- a/README.md +++ b/README.md @@ -122,18 +122,18 @@ Try it out and report bugs / suggestions! -[Configure]: https://github.com/vaxerski/Hyprland/wiki/Configuring-Hyprland +[Configure]: https://github.com/hyprwm/Hyprland/wiki/Configuring-Hyprland [Discord]: https://discord.gg/hQ9XvMUjjr -[Stars]: https://starchart.cc/vaxerski/Hyprland -[Hypr]: https://github.com/vaxerski/Hypr +[Stars]: https://starchart.cc/hyprwm/Hyprland +[Hypr]: https://github.com/hyprwm/Hypr -[Pull Requests]: https://github.com/vaxerski/Hyprland/pulls -[Issues]: https://github.com/vaxerski/Hyprland/issues -[Todo]: https://github.com/vaxerski/Hyprland/projects?type=beta +[Pull Requests]: https://github.com/hyprwm/Hyprland/pulls +[Issues]: https://github.com/hyprwm/Hyprland/issues +[Todo]: https://github.com/hyprwm/Hyprland/projects?type=beta -[Contribute]: https://github.com/vaxerski/Hyprland/wiki/Contributing-&-Debugging -[Install]: https://github.com/vaxerski/Hyprland/wiki/Installation -[Quick Start]: https://github.com/vaxerski/Hyprland/wiki/Quick-start +[Contribute]: https://github.com/hyprwm/Hyprland/wiki/Contributing-&-Debugging +[Install]: https://github.com/hyprwm/Hyprland/wiki/Installation +[Quick Start]: https://github.com/hyprwm/Hyprland/wiki/Quick-start [License]: LICENSE @@ -156,12 +156,12 @@ Try it out and report bugs / suggestions! -[Badge Workflow]: https://github.com/vaxerski/Hyprland/actions/workflows/ci.yaml/badge.svg +[Badge Workflow]: https://github.com/hyprwm/Hyprland/actions/workflows/ci.yaml/badge.svg [Badge Discord]: https://img.shields.io/badge/Join%20the-Discord%20server-6666ff -[Badge Issues]: https://img.shields.io/github/issues/vaxerski/Hyprland -[Badge Pull Requests]: https://img.shields.io/github/issues-pr/vaxerski/Hyprland -[Badge Language]: https://img.shields.io/github/languages/top/vaxerski/Hyprland -[Badge License]: https://img.shields.io/github/license/vaxerski/Hyprland -[Badge Lines]: https://img.shields.io/tokei/lines/github/vaxerski/Hyprland +[Badge Issues]: https://img.shields.io/github/issues/hyprwm/Hyprland +[Badge Pull Requests]: https://img.shields.io/github/issues-pr/hyprwm/Hyprland +[Badge Language]: https://img.shields.io/github/languages/top/hyprwm/Hyprland +[Badge License]: https://img.shields.io/github/license/hyprwm/Hyprland +[Badge Lines]: https://img.shields.io/tokei/lines/github/hyprwm/Hyprland [Badge Hi Mom]: https://img.shields.io/badge/Hi-mom!-ff69b4 diff --git a/docs/ISSUE_GUIDELINES.md b/docs/ISSUE_GUIDELINES.md index 60a8ddb1..c7e9933e 100644 --- a/docs/ISSUE_GUIDELINES.md +++ b/docs/ISSUE_GUIDELINES.md @@ -26,6 +26,7 @@ If your bug is one that doesn't crash Hyprland, but feels like invalid behavior, If your bug crashes Hyprland, append additionally: - The Hyprland log - Coredump / Coredump analysis (with a stacktrace) +- Your config **Important**: Please do NOT use any package for reporting bugs! Clone and compile from source. diff --git a/example/hyprland.conf b/example/hyprland.conf index 30c8559e..a42f0550 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -3,6 +3,11 @@ # # Refer to the wiki for more information. +# +# Please note not all available settings / options are set here. +# For a full list, see the wiki (basic and advanced configuring) +# + monitor=,1280x720@60,0x0,1 workspace=DP-1,1 diff --git a/flake.lock b/flake.lock index 2b1f3cec..ca1c9328 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1656239181, - "narHash": "sha256-wW1xRFBn376yGloXZ4QzBE4hjipMawpV18Lshd9QSPw=", + "lastModified": 1657447684, + "narHash": "sha256-FCP9AuU1q6PE3vOeM5SFf58f/UKPBAsoSGDUGamNBbo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "f2537a505d45c31fe5d9c27ea9829b6f4c4e6ac5", + "rev": "5f43d8b088d3771274bcfb69d3c7435b1121ac88", "type": "github" }, "original": { @@ -26,11 +26,11 @@ "flake": false, "locked": { "host": "gitlab.freedesktop.org", - "lastModified": 1655824477, - "narHash": "sha256-1kskHOLsnisR3kqIL5IHrQbQG/4xoXxeEf1ExMV6/RU=", + "lastModified": 1656865312, + "narHash": "sha256-xtQ0zwJZwN8sciruveM10CzKz6TWxBY8SyXa8E4jly4=", "owner": "wlroots", "repo": "wlroots", - "rev": "5c4384a1330faedf975c8b8644881d50390f3613", + "rev": "5dc1d4671dd2ca3c1f0f09587c463fdbb542f0a4", "type": "gitlab" }, "original": { diff --git a/flake.nix b/flake.nix index b1f621fc..5ad90c4a 100644 --- a/flake.nix +++ b/flake.nix @@ -32,7 +32,8 @@ src = inputs.wlroots; }); hyprland = prev.callPackage ./nix/default.nix { - version = "0.6.2beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")); + stdenv = prev.gcc12Stdenv; + version = "0.7.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")); wlroots = wlroots-hyprland; }; hyprland-debug = hyprland.override {debug = true;}; @@ -47,6 +48,16 @@ default = self.packages.${system}.hyprland; }); + devShells = genSystems (system: { + default = pkgsFor.${system}.mkShell.override {stdenv = pkgsFor.${system}.gcc12Stdenv;} { + name = "hyprland-shell"; + inputsFrom = [ + self.packages.${system}.wlroots-hyprland + self.packages.${system}.hyprland + ]; + }; + }); + formatter = genSystems (system: pkgsFor.${system}.alejandra); nixosModules.default = import ./nix/module.nix self; diff --git a/hyprctl/Makefile b/hyprctl/Makefile index 0e997886..cd1df201 100644 --- a/hyprctl/Makefile +++ b/hyprctl/Makefile @@ -1,4 +1,4 @@ all: - g++ -std=c++20 ./main.cpp -o ./hyprctl + g++ -std=c++23 ./main.cpp -o ./hyprctl clean: - rm ./hyprctl \ No newline at end of file + rm ./hyprctl diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index a1a1122d..92ab4f5e 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -14,9 +14,11 @@ #include #include #include +#include -const std::string USAGE = R"#(usage: hyprctl [command] [(opt)args] +const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args] +commands: monitors workspaces clients @@ -27,8 +29,13 @@ const std::string USAGE = R"#(usage: hyprctl [command] [(opt)args] keyword version kill + splash hyprpaper - reload)#"; + reload + +flags: + j -> output in JSON +)#"; void request(std::string arg) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); @@ -153,7 +160,7 @@ void dispatchRequest(int argc, char** argv) { return; } - std::string rq = "dispatch " + std::string(argv[2]) + " " + std::string(argv[3]); + std::string rq = "/dispatch " + std::string(argv[2]) + " " + std::string(argv[3]); request(rq); } @@ -180,12 +187,21 @@ void hyprpaperRequest(int argc, char** argv) { requestHyprpaper(rq); } -void batchRequest(int argc, char** argv) { - std::string rq = "[[BATCH]]" + std::string(argv[2]); +void batchRequest(std::string arg) { + std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1); request(rq); } +std::deque splitArgs(int argc, char** argv) { + std::deque result; + + for (auto i = 1 /* skip the executable */; i < argc; ++i) + result.push_back(std::string(argv[i])); + + return result; +} + int main(int argc, char** argv) { int bflag = 0, sflag = 0, index, c; @@ -194,20 +210,47 @@ int main(int argc, char** argv) { return 1; } - if (!strcmp(argv[1], "monitors")) request("monitors"); - else if (!strcmp(argv[1], "clients")) request("clients"); - else if (!strcmp(argv[1], "workspaces")) request("workspaces"); - else if (!strcmp(argv[1], "activewindow")) request("activewindow"); - else if (!strcmp(argv[1], "layers")) request("layers"); - else if (!strcmp(argv[1], "version")) request("version"); - else if (!strcmp(argv[1], "kill")) request("kill"); - else if (!strcmp(argv[1], "devices")) request("devices"); - else if (!strcmp(argv[1], "reload")) request("reload"); - else if (!strcmp(argv[1], "dispatch")) dispatchRequest(argc, argv); - else if (!strcmp(argv[1], "keyword")) keywordRequest(argc, argv); - else if (!strcmp(argv[1], "hyprpaper")) hyprpaperRequest(argc, argv); - else if (!strcmp(argv[1], "--batch")) batchRequest(argc, argv); - else if (!strcmp(argv[1], "--help")) printf("%s", USAGE.c_str()); + std::string fullRequest = ""; + std::string fullArgs = ""; + const auto ARGS = splitArgs(argc, argv); + + for (auto i = 0; i < ARGS.size(); ++i) { + if (ARGS[i].contains("-")) { + // parse + if (ARGS[i] == "-j" && !fullArgs.contains("j")) { + fullArgs += "j"; + } else if (ARGS[i] == "--batch") { + fullRequest = "--batch "; + } else { + printf("%s\n", USAGE.c_str()); + return 1; + } + + continue; + } + + fullRequest += ARGS[i] + " "; + } + + fullRequest.pop_back(); // remove trailing space + + fullRequest = fullArgs + "/" + fullRequest; + + if (fullRequest.contains("/--batch")) batchRequest(fullRequest); + else if (fullRequest.contains("/monitors")) request(fullRequest); + else if (fullRequest.contains("/clients")) request(fullRequest); + else if (fullRequest.contains("/workspaces")) request(fullRequest); + else if (fullRequest.contains("/activewindow")) request(fullRequest); + else if (fullRequest.contains("/layers")) request(fullRequest); + else if (fullRequest.contains("/version")) request(fullRequest); + else if (fullRequest.contains("/kill")) request(fullRequest); + else if (fullRequest.contains("/splash")) request(fullRequest); + else if (fullRequest.contains("/devices")) request(fullRequest); + else if (fullRequest.contains("/reload")) request(fullRequest); + else if (fullRequest.contains("/dispatch")) dispatchRequest(argc, argv); + else if (fullRequest.contains("/keyword")) keywordRequest(argc, argv); + else if (fullRequest.contains("/hyprpaper")) hyprpaperRequest(argc, argv); + else if (fullRequest.contains("/--help")) printf("%s", USAGE.c_str()); else { printf("%s\n", USAGE.c_str()); return 1; diff --git a/meson.build b/meson.build index 00628761..294b1ef6 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,8 @@ project('Hyprland', 'cpp', 'c', - version : '0.6.2beta', - default_options : ['warning_level=2', 'cpp_std=c++20', 'default_library=static', 'optimization=3']) + version : '0.7.0beta', + default_options : ['warning_level=2', 'default_library=static', 'optimization=3']) + +add_global_arguments('-std=c++23', language: 'cpp') add_project_arguments( [ diff --git a/nix/default.nix b/nix/default.nix index 495345fd..8ad64f2f 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -61,6 +61,11 @@ stdenv.mkDerivation { ./meson-build.patch ]; + # Fix hardcoded paths to /usr installation + postPatch = '' + sed -i "s#/usr#$out#" src/render/OpenGL.cpp + ''; + passthru.providedSessions = ["hyprland"]; meta = with lib; { diff --git a/nix/module.nix b/nix/module.nix index 383eebb7..a7460b34 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -19,7 +19,7 @@ in { package = mkOption { type = types.package; - default = pkgs.hyprland or self.packages.${pkgs.system}.default; + default = self.packages.${pkgs.system}.default; defaultText = literalExpression ".packages..default"; example = literalExpression ".packages..default.override { }"; description = '' diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 0d8698a6..da6ba1c5 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1,4 +1,16 @@ #include "Compositor.hpp" +#include "helpers/Splashes.hpp" +#include + +int handleCritSignal(int signo, void* data) { + Debug::log(LOG, "Hyprland received signal %d", signo); + + if (signo == SIGTERM || signo == SIGINT || signo == SIGKILL) { + g_pCompositor->cleanup(); + } + + return 0; // everything went fine +} CCompositor::CCompositor() { m_szInstanceSignature = GIT_COMMIT_HASH + std::string("_") + std::to_string(time(NULL)); @@ -22,29 +34,36 @@ CCompositor::CCompositor() { Debug::log(INFO, "If you are crashing, or encounter any bugs, please consult https://github.com/hyprwm/Hyprland/wiki/Crashing-and-bugs\n\n"); + setRandomSplash(); + + Debug::log(LOG, "\nCurrent splash: %s\n\n", m_szCurrentSplash.c_str()); + m_sWLDisplay = wl_display_create(); + m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay); + + // register crit signal handler + wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr); + //wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr); + m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay); if (!m_sWLRBackend) { Debug::log(CRIT, "m_sWLRBackend was NULL!"); - RIP("m_sWLRBackend NULL!"); - return; + throw std::runtime_error("wlr_backend_autocreate() failed!"); } m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend); if (m_iDRMFD < 0) { Debug::log(CRIT, "Couldn't query the DRM FD!"); - RIP("DRMFD NULL!"); - return; + throw std::runtime_error("wlr_backend_get_drm_fd() failed!"); } m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD); if (!m_sWLRRenderer) { Debug::log(CRIT, "m_sWLRRenderer was NULL!"); - RIP("m_sWLRRenderer NULL!"); - return; + throw std::runtime_error("wlr_gles2_renderer_create_with_drm_fd() failed!"); } wlr_renderer_init_wl_display(m_sWLRRenderer, m_sWLDisplay); @@ -53,16 +72,14 @@ CCompositor::CCompositor() { if (!m_sWLRAllocator) { Debug::log(CRIT, "m_sWLRAllocator was NULL!"); - RIP("m_sWLRAllocator NULL!"); - return; + throw std::runtime_error("wlr_allocator_autocreate() failed!"); } m_sWLREGL = wlr_gles2_renderer_get_egl(m_sWLRRenderer); if (!m_sWLREGL) { Debug::log(CRIT, "m_sWLREGL was NULL!"); - RIP("m_sWLREGL NULL!"); - return; + throw std::runtime_error("wlr_gles2_renderer_get_egl() failed!"); } m_sWLRCompositor = wlr_compositor_create(m_sWLDisplay, m_sWLRRenderer); @@ -124,17 +141,26 @@ CCompositor::CCompositor() { m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay); + m_sWLRIdleInhibitMgr = wlr_idle_inhibit_v1_create(m_sWLDisplay); + wlr_xdg_foreign_v1_create(m_sWLDisplay, m_sWLRForeignRegistry); wlr_xdg_foreign_v2_create(m_sWLDisplay, m_sWLRForeignRegistry); + + m_sWLRPointerGestures = wlr_pointer_gestures_v1_create(m_sWLDisplay); + + m_sWLRSession = wlr_backend_get_session(m_sWLRBackend); } CCompositor::~CCompositor() { - cleanupExit(); + cleanup(); } -void handleCritSignal(int signo) { - g_pCompositor->cleanupExit(); - exit(signo); +void CCompositor::setRandomSplash() { + std::random_device dev; + std::mt19937 engine(dev()); + std::uniform_int_distribution<> distribution(0, SPLASHES.size() - 1); + + m_szCurrentSplash = SPLASHES[distribution(engine)]; } void CCompositor::initAllSignals() { @@ -145,6 +171,9 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLRCursor->events.button, &Events::listen_mouseButton, m_sWLRCursor, "WLRCursor"); addWLSignal(&m_sWLRCursor->events.axis, &Events::listen_mouseAxis, m_sWLRCursor, "WLRCursor"); addWLSignal(&m_sWLRCursor->events.frame, &Events::listen_mouseFrame, m_sWLRCursor, "WLRCursor"); + addWLSignal(&m_sWLRCursor->events.swipe_begin, &Events::listen_swipeBegin, m_sWLRCursor, "WLRCursor"); + addWLSignal(&m_sWLRCursor->events.swipe_update, &Events::listen_swipeUpdate, m_sWLRCursor, "WLRCursor"); + addWLSignal(&m_sWLRCursor->events.swipe_end, &Events::listen_swipeEnd, m_sWLRCursor, "WLRCursor"); addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); addWLSignal(&m_sSeat.seat->events.request_set_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat"); addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); @@ -160,12 +189,12 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLRXDGDecoMgr->events.new_toplevel_decoration, &Events::listen_NewXDGDeco, m_sWLRXDGDecoMgr, "XDGDecoMgr"); addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); - - signal(SIGINT, handleCritSignal); - signal(SIGTERM, handleCritSignal); + addWLSignal(&m_sWLRIdleInhibitMgr->events.new_inhibitor, &Events::listen_newIdleInhibitor, m_sWLRIdleInhibitMgr, "WLRIdleInhibitMgr"); + if (m_sWLRSession) + addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session"); } -void CCompositor::cleanupExit() { +void CCompositor::cleanup() { if (!m_sWLDisplay) return; @@ -180,8 +209,7 @@ void CCompositor::cleanupExit() { g_pXWaylandManager->m_sWLRXWayland = nullptr; } - wl_display_destroy_clients(m_sWLDisplay); - wl_display_destroy(m_sWLDisplay); + wl_display_terminate(m_sWLDisplay); m_sWLDisplay = nullptr; } @@ -245,7 +273,7 @@ void CCompositor::startCompositor() { if (!m_szWLDisplaySocket) { Debug::log(CRIT, "m_szWLDisplaySocket NULL!"); wlr_backend_destroy(m_sWLRBackend); - RIP("m_szWLDisplaySocket NULL!"); + throw std::runtime_error("m_szWLDisplaySocket was null! (wl_display_add_socket_auto failed)"); } setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket, 1); @@ -258,7 +286,7 @@ void CCompositor::startCompositor() { Debug::log(CRIT, "Backend did not start!"); wlr_backend_destroy(m_sWLRBackend); wl_display_destroy(m_sWLDisplay); - RIP("Backend did not start!"); + throw std::runtime_error("The backend could not start!"); } wlr_xcursor_manager_set_cursor_image(m_sWLRXCursorMgr, "left_ptr", m_sWLRCursor); @@ -361,6 +389,12 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) { const auto PMONITOR = getMonitorFromVector(pos); if (PMONITOR->specialWorkspaceOpen) { + for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { + wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; + if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->m_bHidden) + return (*w).get(); + } + for (auto& w : m_vWindows) { wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->m_bHidden) @@ -404,14 +438,29 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) { return nullptr; } +void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) { + const auto DATA = (SExtensionFindingData*)data; + + wlr_box box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height}; + + if (wlr_box_contains_point(&box, DATA->vec.x, DATA->vec.y)) + *DATA->found = surface; +} + CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) { const auto PMONITOR = getMonitorFromVector(pos); // special workspace if (PMONITOR->specialWorkspaceOpen) { + for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { + wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; + if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->m_bHidden && (*w)->m_iX11Type != 2) + return (*w).get(); + } + for (auto& w : m_vWindows) { wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; - if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bHidden) + if (!w->m_bIsFloating && w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bHidden && w->m_iX11Type != 2) return w.get(); } } @@ -419,13 +468,37 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) { // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; - if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden) - return w->get(); + if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && (*w)->m_iX11Type != 2) { + if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y)) + return w->get(); + + if (!(*w)->m_bIsX11) { + wlr_surface* resultSurf = nullptr; + Vector2D origin =(*w)->m_vRealPosition.vec(); + SExtensionFindingData data = {origin, pos, &resultSurf}; + wlr_xdg_surface_for_each_popup_surface((*w)->m_uSurface.xdg, findExtensionForVector2D, &data); + + if (resultSurf) + return w->get(); + } + } } + // for windows, we need to check their extensions too, first. + for (auto& w : m_vWindows) { + if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden && w->m_iX11Type != 2) { + wlr_surface* resultSurf = nullptr; + Vector2D origin = w->m_vRealPosition.vec(); + SExtensionFindingData data = {origin, pos, &resultSurf}; + wlr_xdg_surface_for_each_popup_surface(w->m_uSurface.xdg, findExtensionForVector2D, &data); + + if (resultSurf) + return w.get(); + } + } for (auto& w : m_vWindows) { wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; - if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden) + if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden && w->m_iX11Type != 2) return w.get(); } @@ -436,6 +509,12 @@ CWindow* CCompositor::windowFromCursor() { const auto PMONITOR = getMonitorFromCursor(); if (PMONITOR->specialWorkspaceOpen) { + for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { + wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; + if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && !(*w)->m_bHidden) + return (*w).get(); + } + for (auto& w : m_vWindows) { wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped) @@ -536,7 +615,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { // we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window if (windowValidMapped(PLASTWINDOW)) { - updateWindowBorderColor(PLASTWINDOW); + updateWindowAnimatedDecorationValues(PLASTWINDOW); if (PLASTWINDOW->m_bIsX11) { wlr_seat_keyboard_notify_clear_focus(m_sSeat.seat); @@ -559,7 +638,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { const auto POINTERLOCAL = g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.goalv(); wlr_seat_pointer_notify_enter(m_sSeat.seat, PWINDOWSURFACE, POINTERLOCAL.x, POINTERLOCAL.y); - updateWindowBorderColor(pWindow); + updateWindowAnimatedDecorationValues(pWindow); // Send an event g_pEventManager->postEvent(SHyprIPCEvent("activewindow", g_pXWaylandManager->getAppIDClass(pWindow) + "," + pWindow->m_szTitle)); @@ -573,12 +652,16 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) { if (m_sSeat.seat->keyboard_state.focused_surface == pSurface || (pWindowOwner && m_sSeat.seat->keyboard_state.focused_surface == g_pXWaylandManager->getWindowSurface(pWindowOwner))) return; // Don't focus when already focused on this. - if (!pSurface) - return; - // Unfocus last surface if should - if (m_pLastFocus && m_sSeat.seat->keyboard_state.focused_surface && wlr_surface_is_xdg_surface(m_pLastFocus)) - wlr_xdg_toplevel_set_activated(wlr_xdg_surface_from_wlr_surface(m_pLastFocus)->toplevel, false); + if (m_pLastFocus && ((m_sSeat.seat->keyboard_state.focused_surface && wlr_surface_is_xdg_surface(m_pLastFocus)) || !pSurface)) + g_pXWaylandManager->activateSurface(m_pLastFocus, false); + + if (!pSurface) { + wlr_seat_keyboard_clear_focus(m_sSeat.seat); + g_pEventManager->postEvent(SHyprIPCEvent("activewindow", ",")); // unfocused + return; + } + const auto KEYBOARD = wlr_seat_get_keyboard(m_sSeat.seat); @@ -598,6 +681,9 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) { Debug::log(LOG, "Set keyboard focus to surface %x, with window name: %s", pSurface, pWindowOwner->m_szTitle.c_str()); else Debug::log(LOG, "Set keyboard focus to surface %x", pSurface); + + g_pXWaylandManager->activateSurface(pSurface, false); + m_pLastFocus = pSurface; } bool CCompositor::windowValidMapped(CWindow* pWindow) { @@ -689,6 +775,8 @@ void CCompositor::sanityCheckWorkspaces() { if (it == m_vWorkspaces.end()) break; + + continue; } if ((*it)->m_iID == SPECIAL_WORKSPACE_ID && WINDOWSONWORKSPACE == 0) { @@ -700,6 +788,8 @@ void CCompositor::sanityCheckWorkspaces() { if (it == m_vWorkspaces.end()) break; + + continue; } } } @@ -773,9 +863,12 @@ void CCompositor::moveWindowToTop(CWindow* pWindow) { } } -void CCompositor::cleanupFadingOut() { +void CCompositor::cleanupFadingOut(const int& monid) { for (auto& w : m_vWindowsFadingOut) { + if (w->m_iMonitorID != (long unsigned int)monid) + continue; + bool valid = windowExists(w); if (!valid || !w->m_bFadingOut || w->m_fAlpha.fl() == 0.f) { @@ -788,11 +881,16 @@ void CCompositor::cleanupFadingOut() { m_vWindowsFadingOut.erase(std::remove(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), w)); Debug::log(LOG, "Cleanup: destroyed a window"); + + glFlush(); // to free mem NOW. return; } } for (auto& ls : m_vSurfacesFadingOut) { + if (ls->monitorID != monid) + continue; + if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) { for (auto& m : m_vMonitors) { for (auto& lsl : m->m_aLayerSurfaceLists) { @@ -808,6 +906,7 @@ void CCompositor::cleanupFadingOut() { Debug::log(LOG, "Cleanup: destroyed a layersurface"); + glFlush(); // to free mem NOW. return; } } @@ -910,6 +1009,29 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow) { return nullptr; } +CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow) { + bool gotToWindow = false; + for (auto it = m_vWindows.rbegin(); it != m_vWindows.rend(); it++) { + if (it->get() != pWindow && !gotToWindow) + continue; + + if (it->get() == pWindow) { + gotToWindow = true; + continue; + } + + if ((*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->m_bHidden) + return it->get(); + } + + for (auto it = m_vWindows.rbegin(); it != m_vWindows.rend(); it++) { + if (it->get() != pWindow && (*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->m_bHidden) + return it->get(); + } + + return nullptr; +} + int CCompositor::getNextAvailableNamedWorkspace() { int lowest = -1337 + 1; for (auto& w : m_vWorkspaces) { @@ -1032,25 +1154,50 @@ SMonitor* CCompositor::getMonitorInDirection(const char& dir) { return nullptr; } -void CCompositor::updateAllWindowsBorders() { +void CCompositor::updateAllWindowsAnimatedDecorationValues() { for (auto& w : m_vWindows) { if (!w->m_bIsMapped) continue; - updateWindowBorderColor(w.get()); + updateWindowAnimatedDecorationValues(w.get()); } } -void CCompositor::updateWindowBorderColor(CWindow* pWindow) { +void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) { // optimization static int64_t* ACTIVECOL = &g_pConfigManager->getConfigValuePtr("general:col.active_border")->intValue; static int64_t* INACTIVECOL = &g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->intValue; + static auto *const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue; + static auto *const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue; + static auto *const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue; + + // border const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow); if (RENDERDATA.isBorderColor) pWindow->m_cRealBorderColor = RENDERDATA.borderColor; else pWindow->m_cRealBorderColor = CColor(pWindow == m_pLastWindow ? *ACTIVECOL : *INACTIVECOL); + + + // opacity + if (pWindow->m_bIsFullscreen) { + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); + + if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) + pWindow->m_fActiveInactiveAlpha = *PFULLSCREENALPHA; + else { + if (pWindow == m_pLastWindow) + pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alpha * *PACTIVEALPHA; + else + pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive * *PINACTIVEALPHA : *PINACTIVEALPHA; + } + } else { + if (pWindow == m_pLastWindow) + pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alpha * *PACTIVEALPHA; + else + pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive * *PINACTIVEALPHA : *PINACTIVEALPHA; + } } void CCompositor::moveWindowToWorkspace(CWindow* pWindow, const std::string& work) { @@ -1188,4 +1335,20 @@ CWindow* CCompositor::getX11Parent(CWindow* pWindow) { } return nullptr; +} + +void CCompositor::updateWorkspaceWindowDecos(const int& id) { + for (auto& w : m_vWindows) { + if (w->m_iWorkspaceID != id) + continue; + + w->updateWindowDecos(); + } +} + +void CCompositor::scheduleFrameForMonitor(SMonitor* pMonitor) { + if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive) + return; + + wlr_output_schedule_frame(pMonitor->output); } \ No newline at end of file diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 7ad3b7f8..0500387c 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -30,7 +30,9 @@ public: // ------------------ WLR BASICS ------------------ // wl_display* m_sWLDisplay; + wl_event_loop* m_sWLEventLoop; wlr_backend* m_sWLRBackend; + wlr_session* m_sWLRSession; wlr_renderer* m_sWLRRenderer; wlr_allocator* m_sWLRAllocator; wlr_compositor* m_sWLRCompositor; @@ -61,11 +63,14 @@ public: wlr_foreign_toplevel_manager_v1* m_sWLRToplevelMgr; wlr_tablet_manager_v2* m_sWLRTabletManager; wlr_xdg_foreign_registry* m_sWLRForeignRegistry; + wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr; + wlr_pointer_gestures_v1* m_sWLRPointerGestures; // ------------------------------------------------- // const char* m_szWLDisplaySocket; std::string m_szInstanceSignature = ""; + std::string m_szCurrentSplash = "error"; std::vector> m_vMonitors; std::vector> m_vWindows; @@ -77,7 +82,7 @@ public: std::vector m_vSurfacesFadingOut; void startCompositor(); - void cleanupExit(); + void cleanup(); wlr_surface* m_pLastFocus = nullptr; CWindow* m_pLastWindow = nullptr; @@ -86,6 +91,7 @@ public: SSeat m_sSeat; bool m_bReadyToProcess = false; + bool m_bSessionActive = true; // ------------------------------------------------- // @@ -99,7 +105,7 @@ public: bool windowExists(CWindow*); bool windowValidMapped(CWindow*); CWindow* vectorToWindow(const Vector2D&); - CWindow* vectorToWindowIdeal(const Vector2D&); + CWindow* vectorToWindowIdeal(const Vector2D&); // used only for finding a window to focus on, basically a "findFocusableWindow" CWindow* vectorToWindowTiled(const Vector2D&); wlr_surface* vectorToLayerSurface(const Vector2D&, std::list*, Vector2D*, SLayerSurface**); wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl); @@ -113,6 +119,7 @@ public: CWorkspace* getWorkspaceByName(const std::string&); CWorkspace* getWorkspaceByString(const std::string&); void sanityCheckWorkspaces(); + void updateWorkspaceWindowDecos(const int&); int getWindowsOnWorkspace(const int&); CWindow* getFirstWindowOnWorkspace(const int&); void fixXWaylandWindowsOnWorkspace(const int&); @@ -120,16 +127,17 @@ public: bool doesSeatAcceptInput(wlr_surface*); bool isWindowActive(CWindow*); void moveWindowToTop(CWindow*); - void cleanupFadingOut(); + void cleanupFadingOut(const int& monid); CWindow* getWindowInDirection(CWindow*, char); void deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude = nullptr); CWindow* getNextWindowOnWorkspace(CWindow*); + CWindow* getPrevWindowOnWorkspace(CWindow*); int getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); CWindow* getConstraintWindow(SMouse*); SMonitor* getMonitorInDirection(const char&); - void updateAllWindowsBorders(); - void updateWindowBorderColor(CWindow*); + void updateAllWindowsAnimatedDecorationValues(); + void updateWindowAnimatedDecorationValues(CWindow*); void moveWindowToWorkspace(CWindow*, const std::string&); int getNextAvailableMonitorID(); void moveWorkspaceToMonitor(CWorkspace*, SMonitor*); @@ -137,9 +145,13 @@ public: void setWindowFullscreen(CWindow*, bool, eFullscreenMode); void moveUnmanagedX11ToWindows(CWindow*); CWindow* getX11Parent(CWindow*); + void scheduleFrameForMonitor(SMonitor*); + + std::string explicitConfigPath; private: void initAllSignals(); + void setRandomSplash(); }; diff --git a/src/Window.cpp b/src/Window.cpp index fc09b330..8c8cd147 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -7,6 +7,7 @@ CWindow::CWindow() { m_vRealSize.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); m_cRealBorderColor.create(AVARTYPE_COLOR, &g_pConfigManager->getConfigValuePtr("animations:borders_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:borders")->intValue, &g_pConfigManager->getConfigValuePtr("animations:borders_curve")->strValue, (void*)this, AVARDAMAGE_BORDER); m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); + m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); m_dWindowDecorations.emplace_back(std::make_unique(this)); // put the shadow so it's the first deco (has to be rendered first) } @@ -77,6 +78,18 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() { void CWindow::updateWindowDecos() { for (auto& wd : m_dWindowDecorations) wd->updateWindow(this); + + for (auto& wd : m_vDecosToRemove) { + for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) { + if (it->get() == wd) { + it = m_dWindowDecorations.erase(it); + if (it == m_dWindowDecorations.end()) + break; + } + } + } + + m_vDecosToRemove.clear(); } pid_t CWindow::getPID() { diff --git a/src/Window.hpp b/src/Window.hpp index ca6bcbf6..3bef02b1 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -28,6 +28,7 @@ public: DYNLISTENER(unmapWindow); DYNLISTENER(destroyWindow); DYNLISTENER(setTitleWindow); + DYNLISTENER(setGeometryX11U); DYNLISTENER(fullscreenWindow); DYNLISTENER(newPopupXDG); // DYNLISTENER(newSubsurfaceWindow); @@ -99,11 +100,15 @@ public: // Window decorations std::deque> m_dWindowDecorations; + std::vector m_vDecosToRemove; // Special render data, rules, etc SWindowSpecialRenderData m_sSpecialRenderData; SWindowAdditionalConfigData m_sAdditionalConfigData; + // for alpha + CAnimatedVariable m_fActiveInactiveAlpha; + // For the list lookup bool operator==(const CWindow& rhs) { return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f313b155..e3db1856 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -12,8 +12,15 @@ CConfigManager::CConfigManager() { setDefaultVars(); - static const char* const ENVHOME = getenv("HOME"); - const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf"); + + std::string CONFIGPATH; + if (g_pCompositor->explicitConfigPath == "") { + static const char* const ENVHOME = getenv("HOME"); + CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf"); + } else { + CONFIGPATH = g_pCompositor->explicitConfigPath; + } + configPaths.emplace_back(CONFIGPATH); Debug::disableLogs = &configValues["debug:disable_logs"].intValue; @@ -36,6 +43,10 @@ void CConfigManager::setDefaultVars() { configValues["general:col.active_border"].intValue = 0xffffffff; configValues["general:col.inactive_border"].intValue = 0xff444444; configValues["general:cursor_inactive_timeout"].intValue = 0; + + configValues["misc:disable_hyprland_logo"].intValue = 0; + configValues["misc:disable_splash_rendering"].intValue = 0; + configValues["misc:no_vfr"].intValue = 1; configValues["debug:int"].intValue = 0; configValues["debug:log_damage"].intValue = 0; @@ -66,6 +77,7 @@ void CConfigManager::setDefaultVars() { configValues["dwindle:force_split"].intValue = 0; configValues["dwindle:preserve_split"].intValue = 0; configValues["dwindle:special_scale_factor"].floatValue = 0.8f; + configValues["dwindle:split_width_multiplier"].floatValue = 1.0f; configValues["animations:enabled"].intValue = 1; configValues["animations:speed"].floatValue = 7.f; @@ -102,6 +114,13 @@ void CConfigManager::setDefaultVars() { configValues["input:touchpad:clickfinger_behavior"].intValue = 0; configValues["input:touchpad:middle_button_emulation"].intValue = 0; configValues["input:touchpad:tap-to-click"].intValue = 1; + configValues["input:touchpad:drag_lock"].intValue = 0; + + configValues["gestures:workspace_swipe"].intValue = 0; + configValues["gestures:workspace_swipe_distance"].intValue = 300; + configValues["gestures:workspace_swipe_invert"].intValue = 1; + configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30; + configValues["gestures:workspace_swipe_cancel_ratio"].floatValue = 0.5f; configValues["input:follow_mouse"].intValue = 1; @@ -124,6 +143,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) { cfgValues["clickfinger_behavior"].intValue = 0; cfgValues["middle_button_emulation"].intValue = 0; cfgValues["tap-to-click"].intValue = 1; + cfgValues["drag_lock"].intValue = 0; } void CConfigManager::init() { @@ -147,17 +167,15 @@ void CConfigManager::init() { void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) { if (configValues.find(COMMAND) == configValues.end()) { - if (COMMAND[0] == '$') { - // register a dynamic var - Debug::log(LOG, "Registered dynamic var \"%s\" -> %s", COMMAND.c_str(), VALUE.c_str()); - configDynamicVars[COMMAND.substr(1)] = VALUE; - } else { - parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field."; - } + if (COMMAND.find("device:") != 0 /* devices parsed later */) { + if (COMMAND[0] == '$') { + // register a dynamic var + Debug::log(LOG, "Registered dynamic var \"%s\" -> %s", COMMAND.c_str(), VALUE.c_str()); + configDynamicVars[COMMAND.substr(1)] = VALUE; + } else { + parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field."; + } - if (COMMAND.find("device:") == 0 /* devices parsed later */) { - parseError = ""; - } else { return; } } @@ -191,7 +209,12 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s // Values with 0x are hex const auto VALUEWITHOUTHEX = VALUE.substr(2); CONFIGENTRY->intValue = stol(VALUEWITHOUTHEX, nullptr, 16); - } else + } else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) { + CONFIGENTRY->intValue = 1; + } else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) { + CONFIGENTRY->intValue = 0; + } + else CONFIGENTRY->intValue = stol(VALUE); } catch (...) { Debug::log(WARN, "Error reading value of %s", COMMAND.c_str()); @@ -354,7 +377,7 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string newrule.resolution.x = stoi(curitem.substr(0, curitem.find_first_of('x'))); newrule.resolution.y = stoi(curitem.substr(curitem.find_first_of('x') + 1, curitem.find_first_of('@'))); - if (curitem.find_first_of('@') != std::string::npos) + if (curitem.contains("@")) newrule.refreshRate = stof(curitem.substr(curitem.find_first_of('@') + 1)); nextItem(); @@ -503,8 +526,13 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v return; } - if (KEY != "") - g_pKeybindManager->addKeybind(SKeybind{KEY, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap}); + if (KEY != "") { + if (isNumber(KEY) && std::stoi(KEY) > 9) + g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap}); + else + g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap}); + } + } void CConfigManager::handleUnbind(const std::string& command, const std::string& value) { @@ -550,6 +578,16 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str } +void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) { + if (value.find("remove,") == 0) { + const auto TOREMOVE = value.substr(7); + m_dBlurLSNamespaces.erase(std::remove(m_dBlurLSNamespaces.begin(), m_dBlurLSNamespaces.end(), TOREMOVE)); + return; + } + + m_dBlurLSNamespaces.emplace_back(value); +} + void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) { const auto DISPLAY = value.substr(0, value.find_first_of(',')); @@ -575,6 +613,23 @@ void CConfigManager::handleSource(const std::string& command, const std::string& auto value = rawpath; + if (value.length() < 2) { + Debug::log(ERR, "source= path garbage"); + parseError = "source path " + value + " bogus!"; + return; + } + + if (value[0] == '.') { + auto currentDir = configCurrentPath.substr(0, configCurrentPath.find_last_of('/')); + + if (value[1] == '.') { + auto parentDir = currentDir.substr(0, currentDir.find_last_of('/')); + value.replace(0, 2, parentDir); + } else { + value.replace(0, 1, currentDir); + } + } + if (value[0] == '~') { value.replace(0, 1, std::string(ENVHOME)); } @@ -651,6 +706,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: else if (COMMAND == "animation") handleAnimation(COMMAND, VALUE); else if (COMMAND == "source") handleSource(COMMAND, VALUE); else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE); + else if (COMMAND == "blurls") handleBlurLS(COMMAND, VALUE); else configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE); @@ -663,7 +719,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); // Update window border colors - g_pCompositor->updateAllWindowsBorders(); + g_pCompositor->updateAllWindowsAnimatedDecorationValues(); return retval; } @@ -703,7 +759,7 @@ void CConfigManager::parseLine(std::string& line) { line = line.substr(1); } - if (line.find(" {") != std::string::npos) { + if (line.contains(" {")) { auto cat = line.substr(0, line.find(" {")); transform(cat.begin(), cat.end(), cat.begin(), ::tolower); if (currentCategory.length() != 0) { @@ -717,7 +773,7 @@ void CConfigManager::parseLine(std::string& line) { return; } - if (line.find("}") != std::string::npos && currentCategory != "") { + if (line.contains("}") && currentCategory != "") { currentCategory = ""; return; } @@ -753,32 +809,42 @@ void CConfigManager::loadConfigLoadVars() { m_mAdditionalReservedAreas.clear(); configDynamicVars.clear(); deviceConfigs.clear(); + m_dBlurLSNamespaces.clear(); // paths configPaths.clear(); + std::string CONFIGPATH; + static const char* const ENVHOME = getenv("HOME"); const std::string CONFIGPARENTPATH = ENVHOME + (std::string) "/.config/hypr/"; - const std::string CONFIGPATH = CONFIGPARENTPATH + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf"); + + if (g_pCompositor->explicitConfigPath == "") { + CONFIGPATH = CONFIGPARENTPATH + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf"); + } else { + CONFIGPATH = g_pCompositor->explicitConfigPath; + } configPaths.push_back(CONFIGPATH); - + std::ifstream ifs; ifs.open(CONFIGPATH); if (!ifs.good()) { - Debug::log(WARN, "Config reading error. (No file? Attempting to generate, backing up old one if exists)"); - try { - std::filesystem::rename(CONFIGPATH, CONFIGPATH + ".backup"); - } catch(...) { /* Probably doesn't exist */} + if(g_pCompositor->explicitConfigPath == "") { + Debug::log(WARN, "Config reading error. (No file? Attempting to generate, backing up old one if exists)"); + try { + std::filesystem::rename(CONFIGPATH, CONFIGPATH + ".backup"); + } catch(...) { /* Probably doesn't exist */} - try { - if (!std::filesystem::is_directory(CONFIGPARENTPATH)) - std::filesystem::create_directories(CONFIGPARENTPATH); - } - catch (...) { - parseError = "Broken config file! (Could not create directory)"; - return; + try { + if (!std::filesystem::is_directory(CONFIGPARENTPATH)) + std::filesystem::create_directories(CONFIGPARENTPATH); + } + catch (...) { + parseError = "Broken config file! (Could not create directory)"; + return; + } } std::ofstream ofs; @@ -854,7 +920,7 @@ void CConfigManager::loadConfigLoadVars() { } // Update window border colors - g_pCompositor->updateAllWindowsBorders(); + g_pCompositor->updateAllWindowsAnimatedDecorationValues(); // Force the compositor to fully re-render all monitors for (auto& m : g_pCompositor->m_vMonitors) @@ -1084,3 +1150,12 @@ bool CConfigManager::deviceConfigExists(const std::string& dev) { return it != deviceConfigs.end(); } +bool CConfigManager::shouldBlurLS(const std::string& ns) { + for (auto& bls : m_dBlurLSNamespaces) { + if (bls == ns) { + return true; + } + } + + return false; +} diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index bcb2fbe5..1d281c40 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -65,6 +65,7 @@ public: float getDeviceFloat(const std::string&, const std::string&); std::string getDeviceString(const std::string&, const std::string&); bool deviceConfigExists(const std::string&); + bool shouldBlurLS(const std::string&); SConfigValue* getConfigValuePtr(std::string); @@ -102,6 +103,7 @@ private: std::deque m_dMonitorRules; std::deque m_dWindowRules; + std::deque m_dBlurLSNamespaces; bool firstExecDispatched = false; std::deque firstExecRequests; @@ -127,6 +129,7 @@ private: void handleAnimation(const std::string&, const std::string&); void handleSource(const std::string&, const std::string&); void handleSubmap(const std::string&, const std::string&); + void handleBlurLS(const std::string&, const std::string&); }; inline std::unique_ptr g_pConfigManager; \ No newline at end of file diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index e8afb296..1577e36a 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -9,6 +9,12 @@ PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT, OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. ######################################################################################## + +# +# Please note not all available settings / options are set here. +# For a full list, see the wiki (basic and advanced configuring) +# + autogenerated=1 # remove this line to get rid of the warning on top. monitor=,1920x1080@60,0x0,1 diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index eb6c085c..1e6a8e32 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -13,95 +13,390 @@ #include -std::string monitorsRequest() { +std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string result = ""; - for (auto& m : g_pCompositor->m_vMonitors) { - result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\n", - m->szName.c_str(), m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName.c_str(), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform); + if (format == HyprCtl::FORMAT_JSON) { + result += "["; + + for (auto& m : g_pCompositor->m_vMonitors) { + result += getFormat( +R"#({ + "id": %i, + "name": "%s", + "width": %i, + "height": %i, + "refreshRate": %f, + "x": %i, + "y": %i, + "activeWorkspace": { + "id": %i, + "name": "%s" + }, + "reserved": [%i, %i, %i, %i], + "scale": %.2f, + "transform": %i, + "active": "%s" +},)#", + m->ID, + m->szName.c_str(), + (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, + m->refreshRate, + (int)m->vecPosition.x, (int)m->vecPosition.y, + m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName.c_str(), + (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, + m->scale, + (int)m->transform, + (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no") + ); + } + + // remove trailing comma + result.pop_back(); + + result += "]"; + } else { + for (auto& m : g_pCompositor->m_vMonitors) { + result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tactive: %s\n\n", + m->szName.c_str(), m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName.c_str(), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no")); + } } return result; } -std::string clientsRequest() { +std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string result = ""; - for (auto& w : g_pCompositor->m_vWindows) { - if (w->m_bIsMapped) { - result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\n", - &w, w->m_szTitle.c_str(), (int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, (int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w.get()).c_str(), g_pXWaylandManager->getTitle(w.get()).c_str(), w->getPID()); - + if (format == HyprCtl::FORMAT_JSON) { + result += "["; + + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bIsMapped) { + result += getFormat( +R"#({ + "address": "0x%x", + "at": [%i, %i], + "size": [%i, %i], + "workspace": { + "id": %i, + "name": "%s" + }, + "floating": %i, + "monitor": %i, + "class": "%s", + "title": "%s", + "pid": %i +},)#", + &w, + (int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, + (int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y, + w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), + (int)w->m_bIsFloating, + w->m_iMonitorID, + g_pXWaylandManager->getAppIDClass(w.get()).c_str(), + g_pXWaylandManager->getTitle(w.get()).c_str(), + w->getPID() + ); + } + } + + // remove trailing comma + result.pop_back(); + + result += "]"; + } else { + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bIsMapped) { + result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\n", + &w, w->m_szTitle.c_str(), (int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, (int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w.get()).c_str(), g_pXWaylandManager->getTitle(w.get()).c_str(), w->getPID()); + + } } } return result; } -std::string workspacesRequest() { +std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string result = ""; - for (auto& w : g_pCompositor->m_vWorkspaces) { - result += getFormat("workspace ID %i (%s) on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\n", - w->m_iID, w->m_szName.c_str(), g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow); + if (format == HyprCtl::FORMAT_JSON) { + result += "["; + + for (auto& w : g_pCompositor->m_vWorkspaces) { + result += getFormat( +R"#({ + "id": %i, + "name": "%s", + "monitor": "%s", + "windows": %i, + "hasfullscreen": %i +},)#", + w->m_iID, + w->m_szName.c_str(), + g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), + g_pCompositor->getWindowsOnWorkspace(w->m_iID), + (int)w->m_bHasFullscreenWindow + ); + } + + // remove trailing comma + result.pop_back(); + + result += "]"; + } else { + for (auto& w : g_pCompositor->m_vWorkspaces) { + result += getFormat("workspace ID %i (%s) on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\n", + w->m_iID, w->m_szName.c_str(), g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow); + } } return result; } -std::string activeWindowRequest() { +std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) { const auto PWINDOW = g_pCompositor->m_pLastWindow; if (!g_pCompositor->windowValidMapped(PWINDOW)) return "Invalid"; - return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\n", - PWINDOW, PWINDOW->m_szTitle.c_str(), (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), (int)PWINDOW->m_bIsFloating, (int)PWINDOW->m_iMonitorID, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), g_pXWaylandManager->getTitle(PWINDOW).c_str(), PWINDOW->getPID()); + if (format == HyprCtl::FORMAT_JSON) { + return getFormat( +R"#({ + "address": "0x%x", + "at": [%i, %i], + "size": [%i, %i], + "workspace": { + "id": %i, + "name": "%s" + }, + "floating": %i, + "monitor": %i, + "class": "%s", + "title": "%s", + "pid": %i +})#", + PWINDOW, + (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, + (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, + PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), + (int)PWINDOW->m_bIsFloating, + PWINDOW->m_iMonitorID, + g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), + g_pXWaylandManager->getTitle(PWINDOW).c_str(), + PWINDOW->getPID() + ); + } else { + return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\n", + PWINDOW, PWINDOW->m_szTitle.c_str(), (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), (int)PWINDOW->m_bIsFloating, (int)PWINDOW->m_iMonitorID, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), g_pXWaylandManager->getTitle(PWINDOW).c_str(), PWINDOW->getPID()); + } } -std::string layersRequest() { +std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string result = ""; - for (auto& mon : g_pCompositor->m_vMonitors) { - result += getFormat("Monitor %s:\n"); - int layerLevel = 0; - for (auto& level : mon->m_aLayerSurfaceLists) { - result += getFormat("\tLayer level %i:\n", layerLevel); + if (format == HyprCtl::FORMAT_JSON) { + result += "{\n"; - for (auto& layer : level) { - result += getFormat("\t\tLayer %x: xywh: %i %i %i %i\n", layer, layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height); + for (auto& mon : g_pCompositor->m_vMonitors) { + result += getFormat( +R"#("%s": { + "levels": { +)#", + mon->szName.c_str() + ); + + int layerLevel = 0; + for (auto& level : mon->m_aLayerSurfaceLists) { + result += getFormat( +R"#( + "%i": [ +)#", + layerLevel + ); + for (auto& layer : level) { + result += getFormat( +R"#( { + "address": "0x%x", + "x": %i, + "y": %i, + "w": %i, + "h": %i, + "namespace": "%s" + },)#", + layer, + layer->geometry.x, + layer->geometry.y, + layer->geometry.width, + layer->geometry.height, + layer->szNamespace.c_str() + ); + } + + // remove trailing comma + result.pop_back(); + + if (level.size() > 0) + result += "\n "; + + result += "],"; + + layerLevel++; } - layerLevel++; + // remove trailing comma + result.pop_back(); + + result += "\n }\n},"; + } + + // remove trailing comma + result.pop_back(); + + result += "\n}\n"; + + } else { + for (auto& mon : g_pCompositor->m_vMonitors) { + result += getFormat("Monitor %s:\n", mon->szName.c_str()); + int layerLevel = 0; + for (auto& level : mon->m_aLayerSurfaceLists) { + result += getFormat("\tLayer level %i:\n", layerLevel); + + for (auto& layer : level) { + result += getFormat("\t\tLayer %x: xywh: %i %i %i %i, namespace: %s\n", layer, layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, layer->szNamespace.c_str()); + } + + layerLevel++; + } + result += "\n\n"; } - result += "\n\n"; } return result; } -std::string devicesRequest() { +std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string result = ""; - result += "mice:\n"; + if (format == HyprCtl::FORMAT_JSON) { + result += "{\n"; + result += "\"mice\": [\n"; - for (auto& m : g_pInputManager->m_lMice) { - result += getFormat("\tMouse at %x:\n\t\t%s\n", &m, m.mouse->name); - } + for (auto& m : g_pInputManager->m_lMice) { + result += getFormat( +R"#( { + "address": "0x%x", + "name": "%s" + },)#", + &m, + m.mouse->name + ); + } - result += "\n\nKeyboards:\n"; + // remove trailing comma + result.pop_back(); + result += "\n],\n"; - for (auto& k : g_pInputManager->m_lKeyboards) { - result += getFormat("\tKeyboard at %x:\n\t\t%s\n", &k, k.keyboard->name); - } + result += "\"keyboards\": [\n"; + for (auto& k : g_pInputManager->m_lKeyboards) { + const auto KM = xkb_keymap_layout_get_name(wlr_keyboard_from_input_device(k.keyboard)->keymap, 0); + result += getFormat( +R"#( { + "address": "0x%x", + "name": "%s", + "rules": "%s", + "model": "%s", + "layout": "%s", + "variant": "%s", + "options": "%s", + "active_keymap": "%s" + },)#", + &k, + k.keyboard->name, + k.currentRules.rules.c_str(), + k.currentRules.model.c_str(), + k.currentRules.layout.c_str(), + k.currentRules.variant.c_str(), + k.currentRules.options.c_str(), + KM + ); + } - result += "\n\nTablets:\n"; + // remove trailing comma + result.pop_back(); + result += "\n],\n"; - for (auto& d : g_pInputManager->m_lTabletPads) { - result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : ""); - } + result += "\"tablets\": [\n"; - for (auto& d : g_pInputManager->m_lTablets) { - result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.wlrDevice ? d.wlrDevice->name : ""); - } + for (auto& d : g_pInputManager->m_lTabletPads) { + result += getFormat( +R"#( { + "address": "0x%x", + "type": "tabletPad", + "belongsTo": { + "address": "0x%x", + "name": "%s" + } + },)#", + &d, + d.pTabletParent, + d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "" + ); + } - for (auto& d : g_pInputManager->m_lTabletTools) { - result += getFormat("\tTablet Tool at %x (belongs to %x)\n", &d, d.wlrTabletTool ? d.wlrTabletTool->data : 0); + for (auto& d : g_pInputManager->m_lTablets) { + result += getFormat( +R"#( { + "address": "0x%x", + "name": "%s" + },)#", + &d, + d.wlrDevice ? d.wlrDevice->name : "" + ); + } + + for (auto& d : g_pInputManager->m_lTabletTools) { + result += getFormat( +R"#( { + "address": "0x%x", + "type": "tabletTool", + "belongsTo": "0x%x" + },)#", + &d, + d.wlrTabletTool ? d.wlrTabletTool->data : 0 + ); + } + + // remove trailing comma + if (result[result.size() - 1] == ',') + result.pop_back(); + result += "\n]\n"; + + result += "}\n"; + + } else { + result += "mice:\n"; + + for (auto& m : g_pInputManager->m_lMice) { + result += getFormat("\tMouse at %x:\n\t\t%s\n", &m, m.mouse->name); + } + + result += "\n\nKeyboards:\n"; + + for (auto& k : g_pInputManager->m_lKeyboards) { + const auto KM = xkb_keymap_layout_get_name(wlr_keyboard_from_input_device(k.keyboard)->keymap, 0); + result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM); + } + + result += "\n\nTablets:\n"; + + for (auto& d : g_pInputManager->m_lTabletPads) { + result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : ""); + } + + for (auto& d : g_pInputManager->m_lTablets) { + result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.wlrDevice ? d.wlrDevice->name : ""); + } + + for (auto& d : g_pInputManager->m_lTabletTools) { + result += getFormat("\tTablet Tool at %x (belongs to %x)\n", &d, d.wlrTabletTool ? d.wlrTabletTool->data : 0); + } } return result; @@ -158,7 +453,7 @@ std::string dispatchKeyword(std::string in) { if (COMMAND == "monitor") g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords - if (COMMAND.find("input") != std::string::npos) + if (COMMAND.contains("input")) g_pInputManager->setKeyboardLayout(); // update kb layout Debug::log(LOG, "Hyprctl: keyword %s : %s", COMMAND.c_str(), VALUE.c_str()); @@ -181,6 +476,10 @@ std::string killRequest() { return "ok"; } +std::string splashRequest() { + return g_pCompositor->m_szCurrentSplash; +} + std::string getReply(std::string); std::string dispatchBatch(std::string request) { @@ -216,24 +515,46 @@ std::string dispatchBatch(std::string request) { } std::string getReply(std::string request) { + auto format = HyprCtl::FORMAT_NORMAL; + + // process flags for non-batch requests + if (!request.contains("[[BATCH]]") && request.contains("/")) { + long unsigned int sepIndex = 0; + for (const auto& c : request) { + if (c == '/') { // stop at separator + break; + } + + sepIndex++; + + if (c == 'j') + format = HyprCtl::FORMAT_JSON; + } + + if (sepIndex < request.size()) + request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string + } + if (request == "monitors") - return monitorsRequest(); + return monitorsRequest(format); else if (request == "workspaces") - return workspacesRequest(); + return workspacesRequest(format); else if (request == "clients") - return clientsRequest(); + return clientsRequest(format); else if (request == "kill") return killRequest(); else if (request == "activewindow") - return activeWindowRequest(); + return activeWindowRequest(format); else if (request == "layers") - return layersRequest(); + return layersRequest(format); else if (request == "version") return versionRequest(); else if (request == "reload") return reloadRequest(); else if (request == "devices") - return devicesRequest(); + return devicesRequest(format); + else if (request == "splash") + return splashRequest(); else if (request.find("dispatch") == 0) return dispatchRequest(request); else if (request.find("keyword") == 0) @@ -264,6 +585,16 @@ void HyprCtl::tickHyprCtl() { } std::string getRequestFromThread(std::string rq) { + // we need to do something to wake hyprland up if VFR is enabled + + static auto *const PNOVFR = &g_pConfigManager->getConfigValuePtr("misc:no_vfr")->intValue; + + // TODO: is this safe...? + // this might be a race condition + // tested with 2 instances of `watch -n 0.1 hyprctl splash` and seems to not crash so I'll take that as a yes + if (!*PNOVFR) + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_vMonitors.front().get()); + while (HyprCtl::request != "" || HyprCtl::requestMade || HyprCtl::requestReady) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); } diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index 3da4aa07..60559e9f 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -14,4 +14,9 @@ namespace HyprCtl { inline std::string request = ""; inline std::ifstream requestStream; + + enum eHyprCtlOutputFormat { + FORMAT_NORMAL = 0, + FORMAT_JSON + }; }; \ No newline at end of file diff --git a/src/defines.hpp b/src/defines.hpp index 80750c23..375f0119 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -16,8 +16,6 @@ #define ISDEBUG false #endif -#define RIP(format, ... ) { fprintf(stderr, format "\n", ##__VA_ARGS__); exit(EXIT_FAILURE); } - #define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name }; #define DYNLISTENFUNC(name) void listener_##name(void*, void*); #define DYNLISTENER(name) CHyprWLListener hyprListener_##name; diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index 04763be1..349ffe61 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -15,145 +15,179 @@ // // // ---------------------------------------------------- // -void Events::listener_keyboardDestroy(void* owner, void* data) { - SKeyboard* PKEYBOARD = (SKeyboard*)owner; - g_pInputManager->destroyKeyboard(PKEYBOARD); +void Events::listener_keyboardDestroy(void *owner, void *data) { + SKeyboard *PKEYBOARD = (SKeyboard *)owner; + g_pInputManager->destroyKeyboard(PKEYBOARD); - Debug::log(LOG, "Destroyed keyboard %x", PKEYBOARD); + Debug::log(LOG, "Destroyed keyboard %x", PKEYBOARD); } -void Events::listener_keyboardKey(void* owner, void* data) { - SKeyboard* PKEYBOARD = (SKeyboard*)owner; - g_pInputManager->onKeyboardKey((wlr_keyboard_key_event*)data, PKEYBOARD); +void Events::listener_keyboardKey(void *owner, void *data) { + SKeyboard *PKEYBOARD = (SKeyboard *)owner; + g_pInputManager->onKeyboardKey((wlr_keyboard_key_event *)data, PKEYBOARD); } -void Events::listener_keyboardMod(void* owner, void* data) { - SKeyboard* PKEYBOARD = (SKeyboard*)owner; - g_pInputManager->onKeyboardMod(data, PKEYBOARD); +void Events::listener_keyboardMod(void *owner, void *data) { + SKeyboard *PKEYBOARD = (SKeyboard *)owner; + g_pInputManager->onKeyboardMod(data, PKEYBOARD); } -void Events::listener_mouseFrame(wl_listener* listener, void* data) { - wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); +void Events::listener_mouseFrame(wl_listener *listener, void *data) { + wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); } -void Events::listener_mouseMove(wl_listener* listener, void* data) { - g_pInputManager->onMouseMoved((wlr_pointer_motion_event*)data); +void Events::listener_mouseMove(wl_listener *listener, void *data) { + g_pInputManager->onMouseMoved((wlr_pointer_motion_event *)data); } -void Events::listener_mouseMoveAbsolute(wl_listener* listener, void* data) { - g_pInputManager->onMouseWarp((wlr_pointer_motion_absolute_event*)data); +void Events::listener_mouseMoveAbsolute(wl_listener *listener, void *data) { + g_pInputManager->onMouseWarp((wlr_pointer_motion_absolute_event *)data); } -void Events::listener_mouseButton(wl_listener* listener, void* data) { - g_pInputManager->onMouseButton((wlr_pointer_button_event*)data); +void Events::listener_mouseButton(wl_listener *listener, void *data) { + g_pInputManager->onMouseButton((wlr_pointer_button_event *)data); } -void Events::listener_mouseAxis(wl_listener* listener, void* data) { - g_pInputManager->onMouseWheel((wlr_pointer_axis_event*)data); +void Events::listener_mouseAxis(wl_listener *listener, void *data) { + g_pInputManager->onMouseWheel((wlr_pointer_axis_event *)data); } -void Events::listener_requestMouse(wl_listener* listener, void* data) { - const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data; +void Events::listener_requestMouse(wl_listener *listener, void *data) { + const auto EVENT = (wlr_seat_pointer_request_set_cursor_event *)data; - g_pInputManager->processMouseRequest(EVENT); + g_pInputManager->processMouseRequest(EVENT); } -void Events::listener_newInput(wl_listener* listener, void* data) { - const auto DEVICE = (wlr_input_device*)data; - - switch(DEVICE->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - Debug::log(LOG, "Attached a keyboard with name %s", DEVICE->name); - g_pInputManager->newKeyboard(DEVICE); - break; - case WLR_INPUT_DEVICE_POINTER: - Debug::log(LOG, "Attached a mouse with name %s", DEVICE->name); - g_pInputManager->newMouse(DEVICE); - break; - case WLR_INPUT_DEVICE_TOUCH: - Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name); - Debug::log(WARN, "!!!! Hyprland does not directly support touchscreens, bugs may occur !!!!"); - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, DEVICE); - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - Debug::log(LOG, "Attached a tablet tool with name %s", DEVICE->name); - g_pInputManager->newTabletTool(DEVICE); - break; - case WLR_INPUT_DEVICE_TABLET_PAD: - Debug::log(LOG, "Attached a tablet pad with name %s", DEVICE->name); - g_pInputManager->newTabletPad(DEVICE); - break; - default: - Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name); - break; - } - - g_pInputManager->updateCapabilities(DEVICE); -} - -void Events::listener_newConstraint(wl_listener* listener, void* data) { - const auto PCONSTRAINT = (wlr_pointer_constraint_v1*)data; - - Debug::log(LOG, "New mouse constraint at %x", PCONSTRAINT); - - g_pInputManager->m_lConstraints.emplace_back(); - const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back(); - - CONSTRAINT->pMouse = g_pCompositor->m_sSeat.mouse; - CONSTRAINT->constraint = PCONSTRAINT; - - CONSTRAINT->hyprListener_destroyConstraint.initCallback(&PCONSTRAINT->events.destroy, &Events::listener_destroyConstraint, CONSTRAINT, "Constraint"); - CONSTRAINT->hyprListener_setConstraintRegion.initCallback(&PCONSTRAINT->events.set_region, &Events::listener_setConstraintRegion, CONSTRAINT, "Constraint"); - - if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) { - g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT); - } -} - -void Events::listener_destroyConstraint(void* owner, void* data) { - const auto PCONSTRAINT = (SConstraint*)owner; - - if (PCONSTRAINT->pMouse->currentConstraint == PCONSTRAINT->constraint) { - PCONSTRAINT->pMouse->hyprListener_commitConstraint.removeCallback(); - - const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse); - - if (PWINDOW) { - if (PWINDOW->m_bIsX11) { - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, - PCONSTRAINT->constraint->current.cursor_hint.x + PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y + PCONSTRAINT->constraint->current.cursor_hint.y); - - wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->constraint->current.cursor_hint.x, PCONSTRAINT->constraint->current.cursor_hint.y); - } else { - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, - PCONSTRAINT->constraint->current.cursor_hint.x + PWINDOW->m_vRealPosition.vec().x, PCONSTRAINT->constraint->current.cursor_hint.y + PWINDOW->m_vRealPosition.vec().y); - - wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->constraint->current.cursor_hint.x, PCONSTRAINT->constraint->current.cursor_hint.y); - } - } - - PCONSTRAINT->pMouse->currentConstraint = nullptr; - } - - Debug::log(LOG, "Unconstrained mouse from %x", PCONSTRAINT->constraint); - - g_pInputManager->m_lConstraints.remove(*PCONSTRAINT); -} - -void Events::listener_setConstraintRegion(void* owner, void* data) { - // no -} - -void Events::listener_newVirtPtr(wl_listener* listener, void* data) { - const auto EV = (wlr_virtual_pointer_v1_new_pointer_event*)data; - const auto POINTER = EV->new_pointer; - const auto DEVICE = &POINTER->pointer.base; +void Events::listener_newInput(wl_listener *listener, void *data) { + const auto DEVICE = (wlr_input_device *)data; + switch (DEVICE->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + Debug::log(LOG, "Attached a keyboard with name %s", DEVICE->name); + g_pInputManager->newKeyboard(DEVICE); + break; + case WLR_INPUT_DEVICE_POINTER: + Debug::log(LOG, "Attached a mouse with name %s", DEVICE->name); g_pInputManager->newMouse(DEVICE); + break; + case WLR_INPUT_DEVICE_TOUCH: + Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name); + Debug::log(WARN, "!!!! Hyprland does not directly support touchscreens, " + "bugs may occur !!!!"); + wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, DEVICE); + break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + Debug::log(LOG, "Attached a tablet tool with name %s", DEVICE->name); + g_pInputManager->newTabletTool(DEVICE); + break; + case WLR_INPUT_DEVICE_TABLET_PAD: + Debug::log(LOG, "Attached a tablet pad with name %s", DEVICE->name); + g_pInputManager->newTabletPad(DEVICE); + break; + default: + Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name); + break; + } + + g_pInputManager->updateCapabilities(DEVICE); } -void Events::listener_destroyMouse(void* owner, void* data) { - const auto PMOUSE = (SMouse*)owner; +void Events::listener_newConstraint(wl_listener *listener, void *data) { + const auto PCONSTRAINT = (wlr_pointer_constraint_v1 *)data; - g_pInputManager->destroyMouse(PMOUSE->mouse); + Debug::log(LOG, "New mouse constraint at %x", PCONSTRAINT); + + g_pInputManager->m_lConstraints.emplace_back(); + const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back(); + + CONSTRAINT->pMouse = g_pCompositor->m_sSeat.mouse; + CONSTRAINT->constraint = PCONSTRAINT; + + CONSTRAINT->hyprListener_destroyConstraint.initCallback( + &PCONSTRAINT->events.destroy, &Events::listener_destroyConstraint, + CONSTRAINT, "Constraint"); + CONSTRAINT->hyprListener_setConstraintRegion.initCallback( + &PCONSTRAINT->events.set_region, &Events::listener_setConstraintRegion, + CONSTRAINT, "Constraint"); + + if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) { + g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT); + } +} + +void Events::listener_destroyConstraint(void *owner, void *data) { + const auto PCONSTRAINT = (SConstraint *)owner; + + if (PCONSTRAINT->pMouse->currentConstraint == PCONSTRAINT->constraint) { + PCONSTRAINT->pMouse->hyprListener_commitConstraint.removeCallback(); + + const auto PWINDOW = + g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse); + + if (PWINDOW) { + if (PWINDOW->m_bIsX11) { + wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, + PCONSTRAINT->constraint->current.cursor_hint.x + + PWINDOW->m_uSurface.xwayland->x, + PWINDOW->m_uSurface.xwayland->y + + PCONSTRAINT->constraint->current.cursor_hint.y); + + wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, + PCONSTRAINT->constraint->current.cursor_hint.x, + PCONSTRAINT->constraint->current.cursor_hint.y); + } else { + wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, + PCONSTRAINT->constraint->current.cursor_hint.x + + PWINDOW->m_vRealPosition.vec().x, + PCONSTRAINT->constraint->current.cursor_hint.y + + PWINDOW->m_vRealPosition.vec().y); + + wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, + PCONSTRAINT->constraint->current.cursor_hint.x, + PCONSTRAINT->constraint->current.cursor_hint.y); + } + } + + PCONSTRAINT->pMouse->currentConstraint = nullptr; + } + + Debug::log(LOG, "Unconstrained mouse from %x", PCONSTRAINT->constraint); + + g_pInputManager->m_lConstraints.remove(*PCONSTRAINT); +} + +void Events::listener_setConstraintRegion(void *owner, void *data) { + // no +} + +void Events::listener_newVirtPtr(wl_listener *listener, void *data) { + const auto EV = (wlr_virtual_pointer_v1_new_pointer_event *)data; + const auto POINTER = EV->new_pointer; + const auto DEVICE = &POINTER->pointer.base; + + g_pInputManager->newMouse(DEVICE, true); +} + +void Events::listener_destroyMouse(void *owner, void *data) { + const auto PMOUSE = (SMouse *)owner; + + g_pInputManager->destroyMouse(PMOUSE->mouse); +} + +void Events::listener_swipeBegin(wl_listener *listener, void *data) { + const auto EVENT = (wlr_pointer_swipe_begin_event *)data; + + g_pInputManager->onSwipeBegin(EVENT); +} + +void Events::listener_swipeUpdate(wl_listener *listener, void *data) { + const auto EVENT = (wlr_pointer_swipe_update_event *)data; + + g_pInputManager->onSwipeUpdate(EVENT); +} + +void Events::listener_swipeEnd(wl_listener *listener, void *data) { + const auto EVENT = (wlr_pointer_swipe_end_event *)data; + + g_pInputManager->onSwipeEnd(EVENT); } diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 9d1fdb53..63e65fdc 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -49,6 +49,7 @@ namespace Events { DYNLISTENFUNC(fullscreenWindow); DYNLISTENFUNC(activateX11); DYNLISTENFUNC(configureX11); + DYNLISTENFUNC(unmanagedSetGeometry); // Window subsurfaces // LISTENER(newSubsurfaceWindow); @@ -112,4 +113,13 @@ namespace Events { // Renderer destroy LISTENER(RendererDestroy); + + LISTENER(newIdleInhibitor); + + LISTENER(swipeBegin); + LISTENER(swipeEnd); + LISTENER(swipeUpdate); + + // session + LISTENER(sessionActive); }; \ No newline at end of file diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp index 773ba909..0e2f49d5 100644 --- a/src/events/Layers.cpp +++ b/src/events/Layers.cpp @@ -32,8 +32,9 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) { } const auto PMONITOR = (SMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output); - PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].push_back(new SLayerSurface()); - SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].back(); + SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].emplace_back(new SLayerSurface()); + + layerSurface->szNamespace = WLRLAYERSURFACE->_namespace; if (!WLRLAYERSURFACE->output) { WLRLAYERSURFACE->output = g_pCompositor->m_vMonitors.front()->output; // TODO: current mon @@ -50,6 +51,8 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) { WLRLAYERSURFACE->data = layerSurface; layerSurface->monitorID = PMONITOR->ID; + layerSurface->forceBlur = g_pConfigManager->shouldBlurLS(layerSurface->szNamespace); + Debug::log(LOG, "LayerSurface %x (namespace %s layer %d) created on monitor %s", layerSurface->layerSurface, layerSurface->layerSurface->_namespace, layerSurface->layer, PMONITOR->szName.c_str()); } @@ -96,8 +99,6 @@ void Events::listener_mapLayerSurface(void* owner, void* data) { layersurface->layerSurface->mapped = true; - wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output); - // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output); @@ -115,9 +116,15 @@ void Events::listener_mapLayerSurface(void* owner, void* data) { g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); - if (layersurface->layerSurface->current.keyboard_interactive) + if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)) { // don't focus if constrained + wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output); g_pCompositor->focusSurface(layersurface->layerSurface->surface); + const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y); + wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y); + wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y); + } + layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y); wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height}; @@ -150,14 +157,17 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) { if (layersurface->layerSurface->mapped) layersurface->layerSurface->mapped = false; - if (layersurface->layerSurface->surface == g_pCompositor->m_pLastFocus) - g_pCompositor->m_pLastFocus = nullptr; - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output); if (!PMONITOR) return; + // refocus if needed + if (layersurface->layerSurface->surface == g_pCompositor->m_pLastFocus) { + g_pCompositor->m_pLastFocus = nullptr; + g_pInputManager->refocus(); + } + wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); @@ -206,5 +216,8 @@ void Events::listener_commitLayerSurface(void* owner, void* data) { layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y); + // update geom if it changed + layersurface->geometry = {layersurface->geometry.x, layersurface->geometry.y, layersurface->layerSurface->surface->current.width, layersurface->layerSurface->surface->current.height}; + g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y); } \ No newline at end of file diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index c25b1c6a..503d2111 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -157,4 +157,10 @@ void Events::listener_InhibitDeactivate(wl_listener* listener, void* data) { void Events::listener_RendererDestroy(wl_listener* listener, void* data) { Debug::log(LOG, "!!Renderer destroyed!!"); +} + +void Events::listener_sessionActive(wl_listener* listener, void* data) { + Debug::log(LOG, "Session got activated!"); + + g_pCompositor->m_bSessionActive = true; } \ No newline at end of file diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 11527cee..24a8faa7 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -149,10 +149,10 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle); PNEWWORKSPACE->setActive(true); + // if (!pMostHzMonitor || monitorRule.refreshRate > pMostHzMonitor->refreshRate) pMostHzMonitor = PNEWMONITOR; - // if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet g_pCompositor->m_pLastMonitor = PNEWMONITOR; @@ -166,6 +166,11 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { void Events::listener_monitorFrame(void* owner, void* data) { SMonitor* const PMONITOR = (SMonitor*)owner; + if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive) { + Debug::log(WARN, "Attempted to render frame on inactive session!"); + return; // cannot draw on session inactive (different tty) + } + static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now(); @@ -173,6 +178,7 @@ void Events::listener_monitorFrame(void* owner, void* data) { static auto *const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue; static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("general:damage_tracking_internal")->intValue; static auto *const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue; + static auto *const PNOVFR = &g_pConfigManager->getConfigValuePtr("misc:no_vfr")->intValue; static int damageBlinkCleanup = 0; // because double-buffered @@ -181,28 +187,11 @@ void Events::listener_monitorFrame(void* owner, void* data) { g_pDebugOverlay->frameData(PMONITOR); } - // Hack: only check when monitor with top hz refreshes, saves a bit of resources. - // This is for stuff that should be run every frame - if (PMONITOR->ID == pMostHzMonitor->ID) { - g_pCompositor->sanityCheckWorkspaces(); - g_pAnimationManager->tick(); - g_pCompositor->cleanupFadingOut(); - - HyprCtl::tickHyprCtl(); // so that we dont get that race condition multithread bullshit - - g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd - - if (g_pConfigManager->m_bWantsMonitorReload) - g_pConfigManager->performMonitorReload(); - - g_pHyprRenderer->ensureCursorRenderingMode(); // so that the cursor gets hidden/shown if the user requested timeouts - } - if (PMONITOR->framesToSkip > 0) { PMONITOR->framesToSkip -= 1; if (!PMONITOR->noFrameSchedule) - wlr_output_schedule_frame(PMONITOR->output); + g_pCompositor->scheduleFrameForMonitor(PMONITOR); else { Debug::log(LOG, "NoFrameSchedule hit for %s.", PMONITOR->szName.c_str()); } @@ -210,6 +199,22 @@ void Events::listener_monitorFrame(void* owner, void* data) { return; } + // checks // + if (PMONITOR->ID == pMostHzMonitor->ID || !*PNOVFR) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that + g_pCompositor->sanityCheckWorkspaces(); + g_pAnimationManager->tick(); + + HyprCtl::tickHyprCtl(); // so that we dont get that race condition multithread bullshit + + g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd + + if (g_pConfigManager->m_bWantsMonitorReload) + g_pConfigManager->performMonitorReload(); + + g_pHyprRenderer->ensureCursorRenderingMode(); // so that the cursor gets hidden/shown if the user requested timeouts + } + // // + timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -228,10 +233,16 @@ void Events::listener_monitorFrame(void* owner, void* data) { return; } + // we need to cleanup fading out when rendering the appropriate context + g_pCompositor->cleanupFadingOut(PMONITOR->ID); + if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && PMONITOR->forceFullFrames == 0 && damageBlinkCleanup == 0) { pixman_region32_fini(&damage); wlr_output_rollback(PMONITOR->output); - wlr_output_schedule_frame(PMONITOR->output); // we update shit at the monitor's Hz so we need to schedule frames because rollback wont + + if (*PDAMAGEBLINK || *PNOVFR) + g_pCompositor->scheduleFrameForMonitor(PMONITOR); + return; } @@ -266,7 +277,7 @@ void Events::listener_monitorFrame(void* owner, void* data) { // potentially can save on resources. g_pHyprOpenGL->begin(PMONITOR, &damage); - g_pHyprOpenGL->clear(CColor(100, 11, 11, 255)); + g_pHyprOpenGL->clear(CColor(17, 17, 17, 255)); g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now); @@ -319,7 +330,8 @@ void Events::listener_monitorFrame(void* owner, void* data) { wlr_output_commit(PMONITOR->output); - wlr_output_schedule_frame(PMONITOR->output); + if (*PDAMAGEBLINK || *PNOVFR) + g_pCompositor->scheduleFrameForMonitor(PMONITOR); if (*PDEBUGOVERLAY == 1) { const float µs = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f; @@ -353,8 +365,7 @@ void Events::listener_monitorDestroy(void* owner, void* data) { if (!BACKUPMON) { Debug::log(CRIT, "No monitors! Unplugged last! Exiting."); - g_pCompositor->cleanupExit(); - exit(1); + g_pCompositor->cleanup(); return; } @@ -386,7 +397,6 @@ void Events::listener_monitorDestroy(void* owner, void* data) { g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::unique_ptr& el) { return el.get() == pMonitor; })); - // update the pMostHzMonitor if (pMostHzMonitor == pMonitor) { int mostHz = 0; SMonitor* pMonitorMostHz = nullptr; diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp index cfb92f9b..04064696 100644 --- a/src/events/Popups.cpp +++ b/src/events/Popups.cpp @@ -92,6 +92,9 @@ void Events::listener_newPopupXDG(void* owner, void* data) { ASSERT(PWINDOW); + if (!PWINDOW->m_bIsMapped) + return; + Debug::log(LOG, "New layer popup created from XDG window %x -> %s", PWINDOW, PWINDOW->m_szTitle.c_str()); const auto WLRPOPUP = (wlr_xdg_popup*)data; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 3c1d83f5..3d46931e 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -32,6 +32,9 @@ void addViewCoords(void* pWindow, int* x, int* y) { void Events::listener_mapWindow(void* owner, void* data) { CWindow* PWINDOW = (CWindow*)owner; + static auto *const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue; + static auto *const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue; + const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); const auto PWORKSPACE = PMONITOR->specialWorkspaceOpen ? g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); PWINDOW->m_iMonitorID = PMONITOR->ID; @@ -145,7 +148,7 @@ void Events::listener_mapWindow(void* owner, void* data) { try { std::string alphaPart = r.szRule.substr(r.szRule.find_first_of(' ') + 1); - if (alphaPart.find_first_of(' ') != std::string::npos) { + if (alphaPart.contains(' ')) { // we have a comma, 2 values PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart.substr(0, alphaPart.find_first_of(' '))); PWINDOW->m_sSpecialRenderData.alphaInactive = std::stof(alphaPart.substr(alphaPart.find_first_of(' ') + 1)); @@ -163,13 +166,17 @@ void Events::listener_mapWindow(void* owner, void* data) { if (requestedWorkspace != "") { // process requested workspace - if (requestedWorkspace.find_first_of(' ') != std::string::npos) { + if (requestedWorkspace.contains(' ')) { // check for silent - if (requestedWorkspace.find("silent") != std::string::npos) { + if (requestedWorkspace.contains("silent")) { workspaceSilent = true; } requestedWorkspace = requestedWorkspace.substr(0, requestedWorkspace.find_first_of(' ')); + + if (requestedWorkspace == "special") { + workspaceSilent = true; + } } if (!workspaceSilent) { @@ -192,8 +199,8 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto SIZEXSTR = VALUE.substr(0, VALUE.find(" ")); const auto SIZEYSTR = VALUE.substr(VALUE.find(" ") + 1); - const auto SIZEX = SIZEXSTR.find('%') == std::string::npos ? std::stoi(SIZEXSTR) : std::stoi(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.x; - const auto SIZEY = SIZEYSTR.find('%') == std::string::npos ? std::stoi(SIZEYSTR) : std::stoi(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.y; + const auto SIZEX = !SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stoi(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.x; + const auto SIZEY = !SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stoi(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.y; Debug::log(LOG, "Rule size, applying to window %x", PWINDOW); @@ -208,8 +215,8 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto POSXSTR = VALUE.substr(0, VALUE.find(" ")); const auto POSYSTR = VALUE.substr(VALUE.find(" ") + 1); - const auto POSX = POSXSTR.find('%') == std::string::npos ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.x; - const auto POSY = POSYSTR.find('%') == std::string::npos ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.y; + const auto POSX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.x; + const auto POSY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.y; Debug::log(LOG, "Rule move, applying to window %x", PWINDOW); @@ -231,8 +238,11 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10,10); } - if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus) + if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus && PWINDOW->m_iX11Type != 2) { g_pCompositor->focusWindow(PWINDOW); + PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); + } else + PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA); Debug::log(LOG, "Window got assigned a surfaceTreeNode %x", PWINDOW->m_pSurfaceTree); @@ -246,6 +256,9 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_configureX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_configure, &Events::listener_configureX11, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XWayland Window Late"); + + if (PWINDOW->m_iX11Type == 2) + PWINDOW->hyprListener_setGeometryX11U.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_geometry, &Events::listener_unmanagedSetGeometry, PWINDOW, "XWayland Window Late"); } // do the animation thing @@ -254,7 +267,10 @@ void Events::listener_mapWindow(void* owner, void* data) { if (workspaceSilent) { // move the window if (g_pCompositor->m_pLastWindow == PWINDOW) { - g_pKeybindManager->m_mDispatchers["movetoworkspacesilent"](requestedWorkspace); + if (requestedWorkspace != "special") + g_pKeybindManager->m_mDispatchers["movetoworkspacesilent"](requestedWorkspace); + else + g_pKeybindManager->m_mDispatchers["movetoworkspace"]("special"); } else { Debug::log(ERR, "Tried to set workspace silent rule to a nofocus window!"); } @@ -268,9 +284,15 @@ void Events::listener_mapWindow(void* owner, void* data) { g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen); } + PWINDOW->m_vRealPosition.warp(); + PWINDOW->m_vRealSize.warp(); + g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL); } + // recheck idle inhibitors + g_pInputManager->recheckIdleInhibitorStatus(); + PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW, PWINDOW); Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y); @@ -293,6 +315,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { PWINDOW->hyprListener_activateX11.removeCallback(); PWINDOW->hyprListener_configureX11.removeCallback(); PWINDOW->hyprListener_setTitleWindow.removeCallback(); + PWINDOW->hyprListener_setGeometryX11U.removeCallback(); } if (PWINDOW->m_bIsFullscreen) { @@ -350,14 +373,19 @@ void Events::listener_unmapWindow(void* owner, void* data) { // Destroy Foreign Toplevel wlr_foreign_toplevel_handle_v1_destroy(PWINDOW->m_phForeignToplevel); PWINDOW->m_phForeignToplevel = nullptr; + + // recheck idle inhibitors + g_pInputManager->recheckIdleInhibitorStatus(); } void Events::listener_commitWindow(void* owner, void* data) { CWindow* PWINDOW = (CWindow*)owner; - if (!g_pCompositor->windowValidMapped(PWINDOW)) + if (!PWINDOW->m_bMappedX11 || PWINDOW->m_bHidden || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11)) return; + g_pHyprRenderer->damageSurface(g_pXWaylandManager->getWindowSurface(PWINDOW), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y); + // Debug::log(LOG, "Window %x committed", PWINDOW); // SPAM! } @@ -472,6 +500,29 @@ void Events::listener_configureX11(void* owner, void* data) { g_pHyprRenderer->damageWindow(PWINDOW); } +void Events::listener_unmanagedSetGeometry(void* owner, void* data) { + CWindow* PWINDOW = (CWindow*)owner; + + if (!PWINDOW->m_bMappedX11 || PWINDOW->m_bHidden) + return; + + const auto POS = PWINDOW->m_vRealPosition.goalv(); + const auto SIZ = PWINDOW->m_vRealSize.goalv(); + + if (abs(floor(POS.x) - PWINDOW->m_uSurface.xwayland->x) > 2 || abs(floor(POS.y) - PWINDOW->m_uSurface.xwayland->y) > 2 || abs(floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) { + g_pHyprRenderer->damageWindow(PWINDOW); + PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y)); + + if (abs(floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) + PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height)); + + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec()); + g_pCompositor->moveWindowToTop(PWINDOW); + PWINDOW->updateWindowDecos(); + g_pHyprRenderer->damageWindow(PWINDOW); + } +} + void Events::listener_surfaceXWayland(wl_listener* listener, void* data) { const auto XWSURFACE = (wlr_xwayland_surface*)data; diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index ceda2c57..a87fff4f 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -128,10 +128,10 @@ public: case AVARTYPE_COLOR: return m_cValue != m_cGoal; default: - return false; + std::unreachable(); } - return false; // unreachable + std::unreachable(); } void warp() { @@ -149,7 +149,7 @@ public: break; } default: - break; + std::unreachable(); } } diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index cb1d88d6..126600f3 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -137,7 +137,7 @@ float getPlusMinusKeywordResult(std::string source, float relative) { if (source.find_first_of("+") == 0) { try { - if (source.find('.') != std::string::npos) + if (source.contains(".")) result = relative + std::stof(source.substr(1)); else result = relative + std::stoi(source.substr(1)); @@ -147,7 +147,7 @@ float getPlusMinusKeywordResult(std::string source, float relative) { } } else if (source.find_first_of("-") == 0) { try { - if (source.find('.') != std::string::npos) + if (source.contains(".")) result = relative - std::stof(source.substr(1)); else result = relative - std::stoi(source.substr(1)); @@ -157,7 +157,7 @@ float getPlusMinusKeywordResult(std::string source, float relative) { } } else { try { - if (source.find('.') != std::string::npos) + if (source.contains(".")) result = stof(source); else result = stoi(source); diff --git a/src/helpers/Splashes.hpp b/src/helpers/Splashes.hpp new file mode 100644 index 00000000..68681ca2 --- /dev/null +++ b/src/helpers/Splashes.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +inline const std::vector SPLASHES = { + "Woo, animations!", + "It's like Hypr, but better.", + "Release 1.0 when?", + "It's not awesome, it's Hyprland!", + "\"I commit too often, people can't catch up lmao\" - Vaxry", + "This text is random.", + "\"There are reasons to not use rust.\" - Boga", + "Read the wiki.", + "\"Hello everyone this is YOUR daily dose of ‘read the wiki’\" - Vaxry", + "h", + "\"‘why no work’, bro I haven't hacked your pc to get live feeds yet\" - Vaxry", + "Compile, wait for 20 minutes, notice a new commit, compile again.", + "To rice, or not to rice, that is the question.", + "Now available on Fedora!", + // music reference / quote section + "J'remue le ciel, le jour, la nuit.", + "aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!", + "Wir sind schon sehr lang zusammen...", + "I see a red door and I want it painted black.", + "Take on me, take me on...", + "You spin me right round baby right round", + "Stayin' alive, stayin' alive", + "Say no way, say no way ya, no way!", + "Ground control to Major Tom...", + "Alors on danse", + "And all that I can see, is just a yellow lemon tree.", + "Got a one-way ticket to the blues", + "Is this the real life, is this just fantasy", + "What's in your head, in your head?", + "We're all living in America, America, America.", + "I'm still standing, better than I ever did", + "Here comes the sun, bringing you love and shining on everyone", + "Two trailer park girls go round the outside", + "With the lights out, it's less dangerous", + "Here we go back, this is the moment, tonight is the night", + "Now you're just somebody that I used to know...", + "Black bird, black moon, black sky", + "Some legends are told, some turn to dust or to gold", + "Your brain gets smart, but your head gets dumb.", + "Save your mercy for someone who needs it more", + "You're gonna hear my voice when I shout it out loud", + "Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm", + "Súbeme la radio que esta es mi canción", + "I'm beggin', beggin' you", + // + "Join the discord server!", + "Thanks ThatOneCalculator!", + "The AUR packages always work, except for the times they don't.", + "Funny animation compositor woo" +}; \ No newline at end of file diff --git a/src/helpers/Vector2D.cpp b/src/helpers/Vector2D.cpp index acaace13..a96411e6 100644 --- a/src/helpers/Vector2D.cpp +++ b/src/helpers/Vector2D.cpp @@ -1,4 +1,5 @@ #include "Vector2D.hpp" +#include Vector2D::Vector2D(double xx, double yy) { x = xx; @@ -20,4 +21,11 @@ double Vector2D::normalize() { Vector2D Vector2D::floor() { return Vector2D((int)x, (int)y); +} + +Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) { + return Vector2D( + std::clamp(this->x, min.x, max.x == 0 ? INFINITY : max.x), + std::clamp(this->y, min.y, max.y == 0 ? INFINITY : max.y) + ); } \ No newline at end of file diff --git a/src/helpers/Vector2D.hpp b/src/helpers/Vector2D.hpp index 7288a088..7ca52a68 100644 --- a/src/helpers/Vector2D.hpp +++ b/src/helpers/Vector2D.hpp @@ -35,5 +35,7 @@ class Vector2D { return a.x != x || a.y != y; } + Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()); + Vector2D floor(); }; \ No newline at end of file diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 33278053..ce2d7248 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -25,10 +25,14 @@ struct SLayerSurface { int monitorID = -1; + std::string szNamespace = ""; + CAnimatedVariable alpha; bool fadingOut = false; bool readyToDelete = false; + bool forceBlur = false; + // For the list lookup bool operator==(const SLayerSurface& rhs) { return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID; @@ -60,6 +64,26 @@ struct SRenderData { // for custom round values int rounding = -1; // -1 means not set + + // for blurring + bool blur = false; + + // for windows that animate poorly + bool squishOversized = false; +}; + +struct SExtensionFindingData { + Vector2D origin; + Vector2D vec; + wlr_surface** found; +}; + +struct SStringRuleNames { + std::string layout = ""; + std::string model = ""; + std::string variant = ""; + std::string options = ""; + std::string rules = ""; }; struct SKeyboard { @@ -73,7 +97,7 @@ struct SKeyboard { std::string name = ""; - xkb_rule_names currentRules = {0}; + SStringRuleNames currentRules; int repeatRate = 0; int repeatDelay = 0; int numlockOn = -1; @@ -94,6 +118,8 @@ struct SMouse { std::string name = ""; + bool virt = false; + DYNLISTENER(commitConstraint); DYNLISTENER(destroyMouse); @@ -221,3 +247,25 @@ struct STabletPad { return wlrTabletPadV2 == b.wlrTabletPadV2; } }; + +struct SIdleInhibitor { + wlr_idle_inhibitor_v1* pWlrInhibitor = nullptr; + CWindow* pWindow = nullptr; + + DYNLISTENER(Destroy); + + bool operator==(const SIdleInhibitor& b) { + return pWlrInhibitor == b.pWlrInhibitor; + } +}; + +struct SSwipeGesture { + CWorkspace* pWorkspaceBegin = nullptr; + + double delta = 0; + + float avgSpeed = 0; + int speedPoints = 0; + + SMonitor* pMonitor = nullptr; +}; \ No newline at end of file diff --git a/src/helpers/Workspace.hpp b/src/helpers/Workspace.hpp index 2d0c5941..5a3a24ba 100644 --- a/src/helpers/Workspace.hpp +++ b/src/helpers/Workspace.hpp @@ -28,6 +28,7 @@ public: // for animations CAnimatedVariable m_vRenderOffset; CAnimatedVariable m_fAlpha; + bool m_bForceRendering = false; // "scratchpad" bool m_bIsSpecialWorkspace = false; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 7255aae9..ea8d65d0 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -14,7 +14,7 @@ void CHyprError::createQueued() { const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); - const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecSize.x, PMONITOR->vecSize.y); + const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); const auto CAIRO = cairo_create(CAIROSURFACE); @@ -27,12 +27,12 @@ void CHyprError::createQueued() { const auto LINECOUNT = 1 + std::count(m_szQueued.begin(), m_szQueued.end(), '\n'); cairo_set_source_rgba(CAIRO, m_cQueued.r / 255.f, m_cQueued.g / 255.f, m_cQueued.b / 255.f, m_cQueued.a / 255.f); - cairo_rectangle(CAIRO, 0, 0, PMONITOR->vecSize.x, 10 * LINECOUNT); + cairo_rectangle(CAIRO, 0, 0, PMONITOR->vecPixelSize.x, 10 * LINECOUNT); // outline - cairo_rectangle(CAIRO, 0, 0, 1, PMONITOR->vecSize.y); // left - cairo_rectangle(CAIRO, PMONITOR->vecSize.x - 1, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y); // right - cairo_rectangle(CAIRO, 0, PMONITOR->vecSize.y - 1, PMONITOR->vecSize.x, PMONITOR->vecSize.y); // bottom + cairo_rectangle(CAIRO, 0, 0, 1, PMONITOR->vecPixelSize.y); // left + cairo_rectangle(CAIRO, PMONITOR->vecPixelSize.x - 1, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); // right + cairo_rectangle(CAIRO, 0, PMONITOR->vecPixelSize.y - 1, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); // bottom cairo_fill(CAIRO); @@ -70,7 +70,7 @@ void CHyprError::createQueued() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); #endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecSize.x, PMONITOR->vecSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); // delete cairo cairo_destroy(CAIRO); @@ -104,7 +104,7 @@ void CHyprError::draw() { if (g_pHyprOpenGL->m_RenderData.pMonitor != PMONITOR) return; // wrong mon - wlr_box windowBox = {0, 0, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + wlr_box windowBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; g_pHyprOpenGL->renderTexture(m_tTexture, &windowBox, 255.f, 0); } diff --git a/src/includes.hpp b/src/includes.hpp index 2455171d..e8367f50 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -74,6 +74,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -91,6 +92,7 @@ extern "C" { #include #include #include +#include } #undef class @@ -118,4 +120,5 @@ extern "C" { #include "ext-workspace-unstable-v1-protocol.h" -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 33af48a3..2d9eab0f 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -23,19 +23,21 @@ void SDwindleNodeData::recalcSizePosRecursive() { const auto REVERSESPLITRATIO = 2.f - splitRatio; - if (g_pConfigManager->getInt("dwindle:preserve_split") == 0) - splitTop = size.y > size.x; + if (g_pConfigManager->getInt("dwindle:preserve_split") == 0) { + const auto WIDTHMULTIPLIER = g_pConfigManager->getFloat("dwindle:split_width_multiplier"); + splitTop = size.y * WIDTHMULTIPLIER > size.x; + } const auto SPLITSIDE = !splitTop; if (SPLITSIDE) { - // split sidey + // split left/right children[0]->position = position; children[0]->size = Vector2D(size.x / 2.f * splitRatio, size.y); children[1]->position = Vector2D(position.x + size.x / 2.f * splitRatio, position.y); children[1]->size = Vector2D(size.x / 2.f * REVERSESPLITRATIO, size.y); } else { - // split toppy bottomy + // split top/bottom children[0]->position = position; children[0]->size = Vector2D(size.x, size.y / 2.f * splitRatio); children[1]->position = Vector2D(position.x, position.y + size.y / 2.f * splitRatio); @@ -93,17 +95,28 @@ SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const int& id) { } void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID); - - if (!PMONITOR){ - Debug::log(ERR, "Orphaned Node %x (workspace ID: %i)!!", pNode, pNode->workspaceID); - return; - } - // Don't set nodes, only windows. if (pNode->isNode) return; + SMonitor* PMONITOR = nullptr; + + if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) { + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->specialWorkspaceOpen) { + PMONITOR = m.get(); + break; + } + } + } else { + PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID); + } + + if (!PMONITOR) { + Debug::log(ERR, "Orphaned Node %x (workspace ID: %i)!!", pNode, pNode->workspaceID); + return; + } + // for gaps outer const bool DISPLAYLEFT = STICKS(pNode->position.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x); const bool DISPLAYRIGHT = STICKS(pNode->position.x + pNode->size.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x); @@ -160,9 +173,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) { } } - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); - - if (PWORKSPACE->m_bIsSpecialWorkspace) { + if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) { // if special, we adjust the coords a bit static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue; @@ -237,16 +248,19 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) { NEWPARENT->pParent = OPENINGON->pParent; NEWPARENT->isNode = true; // it is a node + const auto WIDTHMULTIPLIER = g_pConfigManager->getFloat("dwindle:split_width_multiplier"); + // if cursor over first child, make it first, etc - const auto SIDEBYSIDE = NEWPARENT->size.x / NEWPARENT->size.y > 1.f; + const auto SIDEBYSIDE = NEWPARENT->size.x > NEWPARENT->size.y * WIDTHMULTIPLIER; NEWPARENT->splitTop = !SIDEBYSIDE; + const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto FORCESPLIT = g_pConfigManager->getInt("dwindle:force_split"); if (FORCESPLIT == 0) { - if ((SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y, NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y + NEWPARENT->size.y)) - || (!SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y, NEWPARENT->position.x + NEWPARENT->size.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) { + if ((SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / WIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y + NEWPARENT->size.y)) + || (!SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / WIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) { // we are hovering over the first node, make PNODE first. NEWPARENT->children[1] = OPENINGON; NEWPARENT->children[0] = PNODE; @@ -275,14 +289,16 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) { } // Update the children - if (NEWPARENT->size.x > NEWPARENT->size.y) { - // split sidey + + + if (NEWPARENT->size.x * WIDTHMULTIPLIER > NEWPARENT->size.y) { + // split left/right OPENINGON->position = NEWPARENT->position; OPENINGON->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y); PNODE->position = Vector2D(NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y); PNODE->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y); } else { - // split toppy bottomy + // split top/bottom OPENINGON->position = NEWPARENT->position; OPENINGON->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 2.f); PNODE->position = Vector2D(NEWPARENT->position.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f); @@ -378,6 +394,8 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) { if (!PWORKSPACE) return; + g_pHyprRenderer->damageMonitor(PMONITOR); + if (PMONITOR->specialWorkspaceOpen) { const auto TOPNODE = getMasterNodeOnWorkspace(SPECIAL_WORKSPACE_ID); @@ -388,9 +406,26 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) { } } - // Ignore any recalc events if we have a fullscreen window. - if (PWORKSPACE->m_bHasFullscreenWindow) + // Ignore any recalc events if we have a fullscreen window, but process if fullscreen mode 2 + if (PWORKSPACE->m_bHasFullscreenWindow) { + if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) + return; + + // massive hack from the fullscreen func + const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + + SDwindleNodeData fakeNode; + fakeNode.pWindow = PFULLWINDOW; + fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; + fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight; + fakeNode.workspaceID = PWORKSPACE->m_iID; + PFULLWINDOW->m_vPosition = fakeNode.position; + PFULLWINDOW->m_vSize = fakeNode.size; + + applyNodeDataToWindow(&fakeNode); + return; + } const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace); @@ -513,6 +548,10 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree pWindow->m_bIsFullscreen = on; PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; + g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); + + g_pEventManager->postEvent(SHyprIPCEvent("fullscreen", std::to_string((int)on))); + if (!pWindow->m_bIsFullscreen) { // if it got its fullscreen disabled, set back its node if it had one const auto PNODE = getNodeFromWindow(pWindow); @@ -562,6 +601,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree // we need to fix XWayland windows by sending them to NARNIA // because otherwise they'd still be recieving mouse events g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace); + + recalculateMonitor(PMONITOR->ID); } void CHyprDwindleLayout::recalculateWindow(CWindow* pWindow) { @@ -637,6 +678,8 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) { PPARENT->recalcSizePosRecursive(); } + + g_pInputManager->refocus(); } std::deque CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) { @@ -820,4 +863,4 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) { std::string CHyprDwindleLayout::getLayoutName() { return "dwindle"; -} \ No newline at end of file +} diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index a7f2facf..9f258b44 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -45,7 +45,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) { Vector2D middlePoint = Vector2D(desiredGeometry.x, desiredGeometry.y) + Vector2D(desiredGeometry.width, desiredGeometry.height) / 2.f; // TODO: detect a popup in a more consistent way. - if (!g_pCompositor->isPointOnAnyMonitor(middlePoint) || (desiredGeometry.x == 0 && desiredGeometry.y == 0)) { + if ((desiredGeometry.x == 0 && desiredGeometry.y == 0)) { // if it's not, fall back to the center placement pWindow->m_vRealPosition = PMONITOR->vecPosition + Vector2D((PMONITOR->vecSize.x - desiredGeometry.width) / 2.f, (PMONITOR->vecSize.y - desiredGeometry.height) / 2.f); } else { @@ -65,10 +65,12 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) { pWindow->m_vRealSize.setValue(pWindow->m_vRealSize.goalv()); } - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); - g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace); + if (pWindow->m_iX11Type != 2) { + g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); + g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace); - g_pCompositor->moveWindowToTop(pWindow); + g_pCompositor->moveWindowToTop(pWindow); + } } void IHyprLayout::onBeginDragWindow() { @@ -210,9 +212,23 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) { // fix pseudo leaving artifacts g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); } else { + pWindow->m_vSize = pWindow->m_vRealSize.vec(); + pWindow->m_vPosition = pWindow->m_vRealPosition.vec(); + onWindowRemovedTiling(pWindow); g_pCompositor->moveWindowToTop(pWindow); + + const auto POS = pWindow->m_vRealPosition.goalv(); + const auto SIZ = pWindow->m_vRealSize.goalv(); + + pWindow->m_vRealPosition.setValueAndWarp(POS + Vector2D(5, 5)); + pWindow->m_vRealSize.setValueAndWarp(SIZ - Vector2D(10, 10)); + + pWindow->m_vRealPosition = POS; + pWindow->m_vRealSize = SIZ; + + g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); } } diff --git a/src/main.cpp b/src/main.cpp index a437430f..9367d870 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,12 +12,22 @@ bool ignoreSudo = false; int main(int argc, char** argv) { if (!getenv("XDG_RUNTIME_DIR")) - RIP("XDG_RUNTIME_DIR not set!"); + throw std::runtime_error("XDG_RUNTIME_DIR is not set!"); // parse some args + std::string configPath; for (int i = 1; i < argc; ++i) { if (!strcmp(argv[i], "--i-am-really-stupid")) ignoreSudo = true; + else if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config")) && argc >= i + 2) { + configPath = std::string(argv[++i]); + Debug::log(LOG, "Using config location %s.", configPath.c_str()); + } else { + std::cout << "Hyprland usage: Hyprland [arg [...]].\n\nArguments:\n" << + "--help -h | Show this help message\n" << + "--config -c | Specify config file to use\n"; + return 1; + } } system("mkdir -p /tmp/hypr"); @@ -37,6 +47,7 @@ int main(int argc, char** argv) { // let's init the compositor. // it initializes basic Wayland stuff in the constructor. g_pCompositor = std::make_unique(); + g_pCompositor->explicitConfigPath = configPath; Debug::log(LOG, "Hyprland init finished."); @@ -46,7 +57,7 @@ int main(int argc, char** argv) { // If we are here it means we got yote. Debug::log(LOG, "Hyprland reached the end."); - g_pCompositor->cleanupExit(); + g_pCompositor->cleanup(); return EXIT_SUCCESS; } diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index e48b4d1e..053267e3 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -53,15 +53,18 @@ void CAnimationManager::tick() { const auto PWINDOW = (CWindow*)av->m_pWindow; const auto PWORKSPACE = (CWorkspace*)av->m_pWorkspace; const auto PLAYER = (SLayerSurface*)av->m_pLayer; + SMonitor* PMONITOR = nullptr; wlr_box WLRBOXPREV = {0,0,0,0}; if (PWINDOW) { WLRBOXPREV = PWINDOW->getFullWindowBoundingBox(); + PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); } else if (PWORKSPACE) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); + PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y}; } else if (PLAYER) { WLRBOXPREV = PLAYER->geometry; + PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D(PLAYER->geometry.x, PLAYER->geometry.y) + Vector2D(PLAYER->geometry.width, PLAYER->geometry.height) / 2.f); } // beziers are with a switch unforto @@ -188,8 +191,11 @@ void CAnimationManager::tick() { // set size and pos if valid, but only if damage policy entire (dont if border for example) - if (g_pCompositor->windowValidMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE) + if (g_pCompositor->windowValidMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && PWINDOW->m_iX11Type != 2) g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv()); + + // manually schedule a frame + g_pCompositor->scheduleFrameForMonitor(PMONITOR); } } @@ -303,7 +309,7 @@ void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) { if (pWindow->m_sAdditionalConfigData.animationStyle != "") { // the window has config'd special anim if (pWindow->m_sAdditionalConfigData.animationStyle.find("slide") == 0) { - if (pWindow->m_sAdditionalConfigData.animationStyle.find(' ') != std::string::npos) { + if (pWindow->m_sAdditionalConfigData.animationStyle.contains(' ')) { // has a direction animationSlide(pWindow, pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find(' ') + 1), close); } else { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index cb091c9f..60e4cdd6 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -41,35 +41,48 @@ void CKeybindManager::addKeybind(SKeybind kb) { void CKeybindManager::removeKeybind(uint32_t mod, const std::string& key) { for (auto it = m_lKeybinds.begin(); it != m_lKeybinds.end(); ++it) { - if (it->modmask == mod && it->key == key) { + if (isNumber(key) && std::stoi(key) > 9) { + const auto KEYNUM = std::stoi(key); + + if (it->modmask == mod && it->keycode == KEYNUM) { + it = m_lKeybinds.erase(it); + + if (it == m_lKeybinds.end()) + break; + } + } + else if (it->modmask == mod && it->key == key) { it = m_lKeybinds.erase(it); + + if (it == m_lKeybinds.end()) + break; } } } uint32_t CKeybindManager::stringToModMask(std::string mods) { uint32_t modMask = 0; - if (mods.find("SHIFT") != std::string::npos) + if (mods.contains("SHIFT")) modMask |= WLR_MODIFIER_SHIFT; - if (mods.find("CAPS") != std::string::npos) + if (mods.contains("CAPS")) modMask |= WLR_MODIFIER_CAPS; - if (mods.find("CTRL") != std::string::npos || mods.find("CONTROL") != std::string::npos) + if (mods.contains("CTRL") || mods.contains("CONTROL")) modMask |= WLR_MODIFIER_CTRL; - if (mods.find("ALT") != std::string::npos) + if (mods.contains("ALT")) modMask |= WLR_MODIFIER_ALT; - if (mods.find("MOD2") != std::string::npos) + if (mods.contains("MOD2")) modMask |= WLR_MODIFIER_MOD2; - if (mods.find("MOD3") != std::string::npos) + if (mods.contains("MOD3")) modMask |= WLR_MODIFIER_MOD3; - if (mods.find("SUPER") != std::string::npos || mods.find("WIN") != std::string::npos || mods.find("LOGO") != std::string::npos || mods.find("MOD4") != std::string::npos) + if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4")) modMask |= WLR_MODIFIER_LOGO; - if (mods.find("MOD5") != std::string::npos) + if (mods.contains("MOD5")) modMask |= WLR_MODIFIER_MOD5; return modMask; } -bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t& key) { +bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t& key, const int& keycode) { bool found = false; if (handleInternalKeybinds(key)) @@ -82,15 +95,24 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t if (modmask != k.modmask || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap) continue; - // oMg such performance hit!!11! - // this little maneouver is gonna cost us 4µs - const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); - const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); - // small TODO: fix 0-9 keys and other modified ones with shift - - if (key != KBKEY && key != KBKEYUPPER) - continue; + if (k.keycode != -1) { + if (keycode != k.keycode) + continue; + + } else { + if (key == 0) + continue; // this is a keycode check run + + // oMg such performance hit!!11! + // this little maneouver is gonna cost us 4µs + const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); + // small TODO: fix 0-9 keys and other modified ones with shift + + if (key != KBKEY && key != KBKEYUPPER) + continue; + } const auto DISPATCHER = m_mDispatchers.find(k.handler); @@ -99,7 +121,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t Debug::log(ERR, "Inavlid handler in a keybind! (handler %s does not exist)", k.handler.c_str()); } else { // call the dispatcher - Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %d)", modmask, KBKEYUPPER); + Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %d)", modmask, key); DISPATCHER->second(k.arg); } @@ -118,11 +140,11 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { if (PSESSION) { const int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; wlr_session_change_vt(PSESSION, TTY); + g_pCompositor->m_bSessionActive = false; for (auto& m : g_pCompositor->m_vMonitors) { - g_pHyprOpenGL->destroyMonitorResources(m.get()); // mark resources as unusable anymore m->noFrameSchedule = true; - m->framesToSkip = 2; + m->framesToSkip = 1; } Debug::log(LOG, "Switched to VT %i, destroyed all render data, frames to skip for each: 2", TTY); @@ -231,9 +253,6 @@ void CKeybindManager::toggleActiveFloating(std::string args) { moveActiveToWorkspace(std::to_string(g_pCompositor->getMonitorFromID(ACTIVEWINDOW->m_iMonitorID)->activeWorkspace)); } - ACTIVEWINDOW->m_vRealPosition.setValue(ACTIVEWINDOW->m_vRealPosition.vec() + Vector2D(5, 5)); - ACTIVEWINDOW->m_vSize = ACTIVEWINDOW->m_vRealPosition.vec() - Vector2D(10, 10); - g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(ACTIVEWINDOW); } } @@ -253,7 +272,14 @@ void CKeybindManager::changeworkspace(std::string args) { int workspaceToChangeTo = 0; std::string workspaceName = ""; - workspaceToChangeTo = getWorkspaceIDFromString(args, workspaceName); + if (args.find("[internal]") == 0) { + workspaceToChangeTo = std::stoi(args.substr(10)); + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); + if (PWORKSPACE) + workspaceName = PWORKSPACE->m_szName; + } else { + workspaceToChangeTo = getWorkspaceIDFromString(args, workspaceName); + } if (workspaceToChangeTo == INT_MAX) { Debug::log(ERR, "Error in changeworkspace, invalid value"); @@ -277,8 +303,6 @@ void CKeybindManager::changeworkspace(std::string args) { const auto OLDWORKSPACEID = PMONITOR->activeWorkspace; // change it - PMONITOR->specialWorkspaceOpen = false; - if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID) PMONITOR->activeWorkspace = workspaceToChangeTo; else @@ -451,7 +475,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { // undo the damage if we are moving to the special workspace if (WORKSPACEID == SPECIAL_WORKSPACE_ID) { - changeworkspace(std::to_string(OLDWORKSPACE->m_iID)); + changeworkspace("[internal]" + std::to_string(OLDWORKSPACE->m_iID)); OLDWORKSPACE->startAnim(true, true, true); toggleSpecialWorkspace(""); g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false, true); @@ -503,8 +527,8 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceToMoveTo); - changeworkspace(std::to_string(OLDWORKSPACEIDONMONITOR)); - changeworkspace(std::to_string(OLDWORKSPACEIDRETURN)); + changeworkspace("[internal]" + std::to_string(OLDWORKSPACEIDONMONITOR)); + changeworkspace("[internal]" + std::to_string(OLDWORKSPACEIDRETURN)); // revert animations PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0,0)); @@ -663,7 +687,7 @@ void CKeybindManager::focusMonitor(std::string arg) { } if (monID > -1 && monID < (int)g_pCompositor->m_vMonitors.size()) { - changeworkspace(std::to_string(g_pCompositor->getMonitorFromID(monID)->activeWorkspace)); + changeworkspace("[internal]" + std::to_string(g_pCompositor->getMonitorFromID(monID)->activeWorkspace)); } else { Debug::log(ERR, "Error in focusMonitor: invalid arg 1"); } @@ -683,7 +707,7 @@ void CKeybindManager::focusMonitor(std::string arg) { } else { for (auto& m : g_pCompositor->m_vMonitors) { if (m->szName == arg) { - changeworkspace(std::to_string(m->activeWorkspace)); + changeworkspace("[internal]" + std::to_string(m->activeWorkspace)); return; } } @@ -788,20 +812,20 @@ void CKeybindManager::workspaceOpt(std::string args) { } void CKeybindManager::exitHyprland(std::string argz) { - g_pCompositor->cleanupExit(); - exit(0); + g_pCompositor->cleanup(); } void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { - if (!isNumber(args) && !isDirection(args)) { - Debug::log(ERR, "moveCurrentWorkspaceToMonitor arg not a number or direction!"); - return; - } + SMonitor* PMONITOR = nullptr; - const auto PMONITOR = isDirection(args) ? g_pCompositor->getMonitorInDirection(args[0]) : g_pCompositor->getMonitorFromID(std::stoi(args)); - - if (!PMONITOR) { - Debug::log(ERR, "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist"); + try { + if (!isNumber(args) && !isDirection(args)) { + PMONITOR = g_pCompositor->getMonitorFromName(args); + } else { + PMONITOR = isDirection(args) ? g_pCompositor->getMonitorInDirection(args[0]) : g_pCompositor->getMonitorFromID(std::stoi(args)); + } + } catch (std::exception& e) { + Debug::log(LOG, "moveCurrentWorkspaceToMonitor: caught exception in monitor", e.what()); return; } @@ -815,18 +839,25 @@ void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { } void CKeybindManager::moveWorkspaceToMonitor(std::string args) { - if (args.find_first_of(' ') == std::string::npos) + if (!args.contains(' ')) return; std::string workspace = args.substr(0, args.find_first_of(' ')); std::string monitor = args.substr(args.find_first_of(' ') + 1); - if (!isNumber(monitor) && !isDirection(monitor)) { - Debug::log(ERR, "moveWorkspaceToMonitor monitor arg not a number or direction!"); + SMonitor* PMONITOR = nullptr; + + try { + if (!isNumber(monitor) && !isDirection(monitor)) { + PMONITOR = g_pCompositor->getMonitorFromName(monitor); + } else { + PMONITOR = isDirection(monitor) ? g_pCompositor->getMonitorInDirection(monitor[0]) : g_pCompositor->getMonitorFromID(std::stoi(monitor)); + } + } catch (std::exception& e) { + Debug::log(LOG, "moveWorkspaceToMonitor: caught exception in monitor", e.what()); return; } - - const auto PMONITOR = isDirection(monitor) ? g_pCompositor->getMonitorInDirection(monitor[0]) : g_pCompositor->getMonitorFromID(std::stoi(monitor)); + if (!PMONITOR){ Debug::log(ERR, "Ignoring moveWorkspaceToMonitor: monitor doesnt exist"); @@ -882,11 +913,16 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) { } } } else { + auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID); + + if (!PSPECIALWORKSPACE) { + // ??? happens sometimes...? + PSPECIALWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique(g_pCompositor->m_pLastMonitor->ID, "special", true)).get(); + } + g_pCompositor->m_pLastMonitor->specialWorkspaceOpen = true; g_pLayoutManager->getCurrentLayout()->recalculateMonitor(g_pCompositor->m_pLastMonitor->ID); - const auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID); - PSPECIALWORKSPACE->startAnim(true, true); PSPECIALWORKSPACE->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID; } @@ -910,7 +946,7 @@ void CKeybindManager::forceRendererReload(std::string args) { } void CKeybindManager::resizeActive(std::string args) { - if (args.find_first_of(' ') == std::string::npos) + if (!args.contains(' ')) return; std::string x = args.substr(0, args.find_first_of(' ')); @@ -959,7 +995,7 @@ void CKeybindManager::resizeActive(std::string args) { } void CKeybindManager::moveActive(std::string args) { - if (args.find_first_of(' ') == std::string::npos) + if (!args.contains(' ')) return; std::string x = args.substr(0, args.find_first_of(' ')); @@ -1007,11 +1043,14 @@ void CKeybindManager::moveActive(std::string args) { g_pLayoutManager->getCurrentLayout()->moveActiveWindow(Vector2D(X, Y)); } -void CKeybindManager::circleNext(std::string) { +void CKeybindManager::circleNext(std::string arg) { if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow)) return; - g_pCompositor->focusWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow)); + if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") + g_pCompositor->focusWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow)); + else + g_pCompositor->focusWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow)); const auto MIDPOINT = g_pCompositor->m_pLastWindow->m_vRealPosition.goalv() + g_pCompositor->m_pLastWindow->m_vRealSize.goalv() / 2.f; @@ -1043,7 +1082,7 @@ void CKeybindManager::focusWindow(std::string regexp) { Debug::log(LOG, "Focusing to window name: %s", w->m_szTitle.c_str()); - changeworkspace(std::to_string(w->m_iWorkspaceID)); + changeworkspace("[internal]" + std::to_string(w->m_iWorkspaceID)); g_pCompositor->focusWindow(w.get()); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 31498677..08a1cba3 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -7,7 +7,8 @@ #include struct SKeybind { - std::string key = 0; + std::string key = ""; + int keycode = -1; uint32_t modmask = 0; std::string handler = ""; std::string arg = ""; @@ -19,7 +20,7 @@ class CKeybindManager { public: CKeybindManager(); - bool handleKeybinds(const uint32_t&, const xkb_keysym_t&); + bool handleKeybinds(const uint32_t&, const xkb_keysym_t&, const int&); void addKeybind(SKeybind); void removeKeybind(uint32_t, const std::string&); uint32_t stringToModMask(std::string); diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 48687163..6ba2fa34 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -36,7 +36,9 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) wlr_xdg_toplevel_set_activated(wlr_xdg_surface_from_wlr_surface(pSurface)->toplevel, activate); else if (wlr_surface_is_xwayland_surface(pSurface)) { wlr_xwayland_surface_activate(wlr_xwayland_surface_from_wlr_surface(pSurface), activate); - wlr_xwayland_surface_restack(wlr_xwayland_surface_from_wlr_surface(pSurface), NULL, XCB_STACK_MODE_ABOVE); + + if (activate) + wlr_xwayland_surface_restack(wlr_xwayland_surface_from_wlr_surface(pSurface), NULL, XCB_STACK_MODE_ABOVE); } } @@ -153,7 +155,7 @@ bool CHyprXWaylandManager::shouldBeFloated(CWindow* pWindow) { if (pWindow->m_uSurface.xwayland->role) { try { std::string winrole = std::string(pWindow->m_uSurface.xwayland->role); - if (winrole.find("pop-up") != std::string::npos || winrole.find("task_dialog") != std::string::npos) { + if (winrole.contains("pop-up") || winrole.contains("task_dialog")) { return true; } } catch (std::exception& e) { @@ -221,6 +223,4 @@ void CHyprXWaylandManager::setWindowFullscreen(CWindow* pWindow, bool fullscreen if (pWindow->m_phForeignToplevel) wlr_foreign_toplevel_handle_v1_set_fullscreen(pWindow->m_phForeignToplevel, fullscreen); - - g_pEventManager->postEvent(SHyprIPCEvent("fullscreen", std::to_string((int)fullscreen))); } \ No newline at end of file diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp new file mode 100644 index 00000000..3efb40c6 --- /dev/null +++ b/src/managers/input/IdleInhibitor.cpp @@ -0,0 +1,54 @@ +#include "InputManager.hpp" +#include "../../Compositor.hpp" + +void Events::listener_newIdleInhibitor(wl_listener* listener, void* data) { + const auto WLRIDLEINHIBITOR = (wlr_idle_inhibitor_v1*)data; + + if (!WLRIDLEINHIBITOR) + return; + + g_pInputManager->newIdleInhibitor(WLRIDLEINHIBITOR); +} + +void CInputManager::newIdleInhibitor(wlr_idle_inhibitor_v1* pInhibitor) { + const auto PINHIBIT = &m_lIdleInhibitors.emplace_back(); + + Debug::log(LOG, "New idle inhibitor registered"); + + PINHIBIT->pWlrInhibitor = pInhibitor; + + PINHIBIT->hyprListener_Destroy.initCallback(&pInhibitor->events.destroy, [](void* owner, void* data){ + + const auto PINH = (SIdleInhibitor*)owner; + + g_pInputManager->m_lIdleInhibitors.remove(*PINH); + + Debug::log(LOG, "Destroyed an idleinhibitor"); + + g_pInputManager->recheckIdleInhibitorStatus(); + + }, PINHIBIT, "IdleInhibitor"); + + PINHIBIT->pWindow = g_pCompositor->getWindowFromSurface(pInhibitor->surface); + + if (PINHIBIT->pWindow) + Debug::log(LOG, "IdleInhibitor got window %x (%s)", PINHIBIT->pWindow, PINHIBIT->pWindow->m_szTitle.c_str()); + + recheckIdleInhibitorStatus(); +} + +void CInputManager::recheckIdleInhibitorStatus() { + + for (auto& ii : m_lIdleInhibitors) { + if (!ii.pWindow) { + wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false); + return; + } else if (g_pHyprRenderer->shouldRenderWindow(ii.pWindow)) { + wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false); + return; + } + } + + wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, true); + return; +} \ No newline at end of file diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 92a06a4c..5f1b1a3a 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -28,6 +28,8 @@ void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) { void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { + static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; + if (!g_pCompositor->m_bReadyToProcess) return; @@ -36,10 +38,13 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { return; } + if (g_pCompositor->m_sSeat.mouse->virt) + return; // don't refocus on virt + Vector2D mouseCoords = getMouseCoordsInternal(); const auto MOUSECOORDSFLOORED = mouseCoords.floor(); - if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored) + if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored && !refocus) return; m_vLastCursorPosFloored = MOUSECOORDSFLOORED; @@ -86,6 +91,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } else { if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) { g_pCompositor->m_sSeat.mouse->constraintActive = true; + didConstraintOnCursor = true; } } } @@ -138,6 +144,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!pFoundWindow->m_bIsX11) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); + surfacePos = Vector2D(-1337, -1337); } else { foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow); surfacePos = pFoundWindow->m_vRealPosition.vec(); @@ -153,9 +160,21 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // then windows if (!foundSurface) { - if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) - pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); - else + if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { + + if (PMONITOR->specialWorkspaceOpen) { + pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); + + if (pFoundWindow && pFoundWindow->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) { + pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + } + } else { + pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); + + if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen)) + pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + } + } else pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); if (pFoundWindow) { @@ -183,6 +202,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat); + if (refocus) { // if we are forcing a refocus, and we don't find a surface, clear the kb focus too! + g_pCompositor->focusSurface(nullptr); + + g_pCompositor->m_pLastWindow = nullptr; + } + return; } @@ -200,7 +225,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } if (pFoundWindow) { - static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; if (*PFOLLOWMOUSE != 1 && !refocus) { if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating)) { // enter if change floating style @@ -384,8 +408,8 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) { Debug::log(ERR, "Keyboard had no name???"); // logic error } - PNEWKEYBOARD->hyprListener_keyboardMod.initCallback(&keyboard->keyboard->events.modifiers, &Events::listener_keyboardMod, PNEWKEYBOARD, "Keyboard"); - PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&keyboard->keyboard->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard"); + PNEWKEYBOARD->hyprListener_keyboardMod.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.modifiers, &Events::listener_keyboardMod, PNEWKEYBOARD, "Keyboard"); + PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard"); PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard"); if (m_pActiveKeyboard) @@ -394,7 +418,7 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) { applyConfigToKeyboard(PNEWKEYBOARD); - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, keyboard->keyboard); + wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard)); Debug::log(LOG, "New keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, keyboard); } @@ -409,6 +433,9 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { ASSERT(pKeyboard); + if (!wlr_keyboard_from_input_device(pKeyboard->keyboard)) + return; + const auto REPEATRATE = HASCONFIG ? g_pConfigManager->getDeviceInt(pKeyboard->name, "repeat_rate") : g_pConfigManager->getInt("input:repeat_rate"); const auto REPEATDELAY = HASCONFIG ? g_pConfigManager->getDeviceInt(pKeyboard->name, "repeat_delay") : g_pConfigManager->getInt("input:repeat_delay"); @@ -421,7 +448,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { const auto OPTIONS = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_options") : g_pConfigManager->getString("input:kb_options"); try { - if (NUMLOCKON == pKeyboard->numlockOn && REPEATDELAY == pKeyboard->repeatDelay && REPEATRATE == pKeyboard->repeatRate && RULES != "" && RULES == std::string(pKeyboard->currentRules.rules) && MODEL == std::string(pKeyboard->currentRules.model) && LAYOUT == std::string(pKeyboard->currentRules.layout) && VARIANT == std::string(pKeyboard->currentRules.variant) && OPTIONS == std::string(pKeyboard->currentRules.options)) { + if (NUMLOCKON == pKeyboard->numlockOn && REPEATDELAY == pKeyboard->repeatDelay && REPEATRATE == pKeyboard->repeatRate && RULES != "" && RULES == pKeyboard->currentRules.rules && MODEL == pKeyboard->currentRules.model && LAYOUT == pKeyboard->currentRules.layout && VARIANT == pKeyboard->currentRules.variant && OPTIONS == pKeyboard->currentRules.options) { Debug::log(LOG, "Not applying config to keyboard, it did not change."); return; } @@ -430,7 +457,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { // we can ignore those and just apply } - wlr_keyboard_set_repeat_info(pKeyboard->keyboard->keyboard, std::max(0, REPEATRATE), std::max(0, REPEATDELAY)); + wlr_keyboard_set_repeat_info(wlr_keyboard_from_input_device(pKeyboard->keyboard), std::max(0, REPEATRATE), std::max(0, REPEATDELAY)); pKeyboard->repeatDelay = REPEATDELAY; pKeyboard->repeatRate = REPEATRATE; @@ -443,7 +470,11 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { .variant = VARIANT.c_str(), .options = OPTIONS.c_str()}; - pKeyboard->currentRules = rules; + pKeyboard->currentRules.rules = RULES; + pKeyboard->currentRules.model = MODEL; + pKeyboard->currentRules.variant = VARIANT; + pKeyboard->currentRules.options = OPTIONS; + pKeyboard->currentRules.layout = LAYOUT; const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); @@ -460,12 +491,16 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { Debug::log(ERR, "Keyboard layout %s with variant %s (rules: %s, model: %s, options: %s) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, rules.options); memset(&rules, 0, sizeof(rules)); - pKeyboard->currentRules = rules; + pKeyboard->currentRules.rules = ""; + pKeyboard->currentRules.model = ""; + pKeyboard->currentRules.variant = ""; + pKeyboard->currentRules.options = ""; + pKeyboard->currentRules.layout = ""; KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); } - wlr_keyboard_set_keymap(pKeyboard->keyboard->keyboard, KEYMAP); + wlr_keyboard_set_keymap(wlr_keyboard_from_input_device(pKeyboard->keyboard), KEYMAP); wlr_keyboard_modifiers wlrMods = {0}; @@ -478,7 +513,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { } if (wlrMods.locked != 0) { - wlr_keyboard_notify_modifiers(pKeyboard->keyboard->keyboard, 0, 0, wlrMods.locked, 0); + wlr_keyboard_notify_modifiers(wlr_keyboard_from_input_device(pKeyboard->keyboard), 0, 0, wlrMods.locked, 0); } xkb_keymap_unref(KEYMAP); @@ -487,11 +522,12 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { Debug::log(LOG, "Set the keyboard layout to %s and variant to %s for keyboard \"%s\"", rules.layout, rules.variant, pKeyboard->keyboard->name); } -void CInputManager::newMouse(wlr_input_device* mouse) { +void CInputManager::newMouse(wlr_input_device* mouse, bool virt) { m_lMice.emplace_back(); const auto PMOUSE = &m_lMice.back(); PMOUSE->mouse = mouse; + PMOUSE->virt = virt; try { PMOUSE->name = std::string(mouse->name); } catch(std::exception& e) { @@ -515,6 +551,11 @@ void CInputManager::newMouse(wlr_input_device* mouse) { libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); } + if ((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "drag_lock") : g_pConfigManager->getInt("input:touchpad:drag_lock")) == 0) + libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_DISABLED); + else + libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); + if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop) if ((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "tap-to-click") : g_pConfigManager->getInt("input:touchpad:tap-to-click")) == 1) libinput_device_config_tap_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_ENABLED); @@ -582,29 +623,31 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar const auto KEYCODE = e->keycode + 8; // Because to xkbcommon it's +8 from libinput const xkb_keysym_t* keysyms; - int syms = xkb_state_key_get_syms(pKeyboard->keyboard->keyboard->xkb_state, KEYCODE, &keysyms); + int syms = xkb_state_key_get_syms(wlr_keyboard_from_input_device(pKeyboard->keyboard)->xkb_state, KEYCODE, &keysyms); - const auto MODS = wlr_keyboard_get_modifiers(pKeyboard->keyboard->keyboard); + const auto MODS = accumulateModsFromAllKBs(); wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat); bool found = false; if (e->state == WL_KEYBOARD_KEY_STATE_PRESSED) { for (int i = 0; i < syms; ++i) - found = g_pKeybindManager->handleKeybinds(MODS, keysyms[i]) || found; + found = g_pKeybindManager->handleKeybinds(MODS, keysyms[i], 0) || found; + + found = g_pKeybindManager->handleKeybinds(MODS, 0, KEYCODE) || found; } else if (e->state == WL_KEYBOARD_KEY_STATE_RELEASED) { // hee hee } if (!found) { - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, pKeyboard->keyboard->keyboard); + wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard)); wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e->time_msec, e->keycode, e->state); } } void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) { - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, pKeyboard->keyboard->keyboard); - wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &pKeyboard->keyboard->keyboard->modifiers); + wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard)); + wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers); } void CInputManager::refocus() { @@ -722,4 +765,15 @@ void CInputManager::updateCapabilities(wlr_input_device* pDev) { } wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, m_uiCapabilities); -} \ No newline at end of file +} + +uint32_t CInputManager::accumulateModsFromAllKBs() { + + uint32_t finalMask = 0; + + for (auto& kb : m_lKeyboards) { + finalMask |= wlr_keyboard_get_modifiers(wlr_keyboard_from_input_device(kb.keyboard)); + } + + return finalMask; +} diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 1a50c585..5e0c86b1 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -22,7 +22,7 @@ public: void onKeyboardMod(void*, SKeyboard*); void newKeyboard(wlr_input_device*); - void newMouse(wlr_input_device*); + void newMouse(wlr_input_device*, bool virt = false); void destroyKeyboard(SKeyboard*); void destroyMouse(wlr_input_device*); @@ -57,9 +57,20 @@ public: std::list m_lTabletTools; std::list m_lTabletPads; + // idle inhibitors + std::list m_lIdleInhibitors; + void newTabletTool(wlr_input_device*); void newTabletPad(wlr_input_device*); void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false); + void newIdleInhibitor(wlr_idle_inhibitor_v1*); + void recheckIdleInhibitorStatus(); + + void onSwipeBegin(wlr_pointer_swipe_begin_event*); + void onSwipeEnd(wlr_pointer_swipe_end_event*); + void onSwipeUpdate(wlr_pointer_swipe_update_event*); + + SSwipeGesture m_sActiveSwipe; SKeyboard* m_pActiveKeyboard = nullptr; @@ -81,6 +92,9 @@ private: STabletTool* ensureTabletToolPresent(wlr_tablet_tool*); void applyConfigToKeyboard(SKeyboard*); + + // for shared mods + uint32_t accumulateModsFromAllKBs(); }; inline std::unique_ptr g_pInputManager; \ No newline at end of file diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp new file mode 100644 index 00000000..98f31945 --- /dev/null +++ b/src/managers/input/Swipe.cpp @@ -0,0 +1,152 @@ +#include "InputManager.hpp" +#include "../../Compositor.hpp" + +void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) { + + static auto *const PSWIPE = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe")->intValue; + + if (e->fingers < 3 || *PSWIPE == 0) + return; + + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); + + Debug::log(LOG, "Starting a swipe from %s", PWORKSPACE->m_szName.c_str()); + + m_sActiveSwipe.pWorkspaceBegin = PWORKSPACE; + m_sActiveSwipe.delta = 0; + m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor; + m_sActiveSwipe.avgSpeed = 0; + m_sActiveSwipe.speedPoints = 0; +} + +void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) { + + if (!m_sActiveSwipe.pWorkspaceBegin) + return; // no valid swipe + + static auto *const PSWIPEPERC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_cancel_ratio")->floatValue; + static auto *const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue; + static auto *const PSWIPEFORC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_min_speed_to_force")->intValue; + + // commit + std::string wsname = ""; + auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname); + auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname); + + const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); + const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + + const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.vec(); + + if ((abs(m_sActiveSwipe.delta) < *PSWIPEDIST * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_sActiveSwipe.avgSpeed < *PSWIPEFORC))) || abs(m_sActiveSwipe.delta) < 2) { + // revert + if (m_sActiveSwipe.delta < 0) { + // to left + PWORKSPACEL->m_vRenderOffset = Vector2D({-m_sActiveSwipe.pMonitor->vecSize.x, 0}); + } else { + // to right + PWORKSPACER->m_vRenderOffset = Vector2D({m_sActiveSwipe.pMonitor->vecSize.x, 0}); + } + + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(); + } else if (m_sActiveSwipe.delta < 0) { + // switch to left + const auto RENDEROFFSET = PWORKSPACEL->m_vRenderOffset.vec(); + + g_pKeybindManager->m_mDispatchers["workspace"]("[internal]" + std::to_string(workspaceIDLeft)); + + PWORKSPACEL->m_vRenderOffset.setValue(RENDEROFFSET); + PWORKSPACEL->m_fAlpha.setValueAndWarp(255.f); + + Debug::log(LOG, "Ended swipe to the left"); + } else { + // switch to right + const auto RENDEROFFSET = PWORKSPACER->m_vRenderOffset.vec(); + + g_pKeybindManager->m_mDispatchers["workspace"]("[internal]" + std::to_string(workspaceIDRight)); + + PWORKSPACER->m_vRenderOffset.setValue(RENDEROFFSET); + PWORKSPACER->m_fAlpha.setValueAndWarp(255.f); + + Debug::log(LOG, "Ended swipe to the right"); + } + + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); + m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f); + + PWORKSPACEL->m_bForceRendering = false; + PWORKSPACER->m_bForceRendering = false; + m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = false; + + m_sActiveSwipe.pWorkspaceBegin = nullptr; + + g_pInputManager->refocus(); +} + +void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) { + if (!m_sActiveSwipe.pWorkspaceBegin) + return; + + static auto *const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue; + static auto *const PSWIPEINVR = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_invert")->intValue; + + m_sActiveSwipe.delta += *PSWIPEINVR ? -e->dx : e->dx; + + m_sActiveSwipe.avgSpeed = (m_sActiveSwipe.avgSpeed * m_sActiveSwipe.speedPoints + abs(e->dx)) / (m_sActiveSwipe.speedPoints + 1); + m_sActiveSwipe.speedPoints++; + + std::string wsname = ""; + auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname); + auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname); + + if (workspaceIDLeft == INT_MAX || workspaceIDRight == INT_MAX || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) + return; + + m_sActiveSwipe.delta = std::clamp(m_sActiveSwipe.delta, (double)-*PSWIPEDIST, (double)*PSWIPEDIST); + + if (m_sActiveSwipe.delta < 0) { + if (workspaceIDLeft > m_sActiveSwipe.pWorkspaceBegin->m_iID){ + m_sActiveSwipe.delta = 0; + return; + } + + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + + PWORKSPACE->m_bForceRendering = true; + + if (workspaceIDLeft != workspaceIDRight) { + const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); + + PWORKSPACER->m_bForceRendering = false; + } + + PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x - m_sActiveSwipe.pMonitor->vecSize.x, 0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0)); + + g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft); + } else { + if (workspaceIDRight < m_sActiveSwipe.pWorkspaceBegin->m_iID){ + m_sActiveSwipe.delta = 0; + return; + } + + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight); + + PWORKSPACE->m_bForceRendering = true; + + if (workspaceIDLeft != workspaceIDRight) { + const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + + PWORKSPACEL->m_bForceRendering = false; + } + + PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x + m_sActiveSwipe.pMonitor->vecSize.x, 0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0)); + + g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight); + } + + g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); + + g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); +} \ No newline at end of file diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 6a62e58e..ba79c458 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -10,7 +10,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { Debug::log(ERR, "Tablet had no name???"); // logic error } - PNEWTABLET->wlrTablet = pDevice->tablet; + PNEWTABLET->wlrTablet = wlr_tablet_from_input_device(pDevice); PNEWTABLET->wlrDevice = pDevice; PNEWTABLET->wlrTabletV2 = wlr_tablet_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice); PNEWTABLET->wlrTablet->data = PNEWTABLET; @@ -27,7 +27,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { Debug::log(LOG, "Removed a tablet"); }, PNEWTABLET, "Tablet"); - PNEWTABLET->hyprListener_Axis.initCallback(&pDevice->tablet->events.axis, [](void* owner, void* data) { + PNEWTABLET->hyprListener_Axis.initCallback(&wlr_tablet_from_input_device(pDevice)->events.axis, [](void* owner, void* data) { const auto EVENT = (wlr_tablet_tool_axis_event*)data; const auto PTAB = (STablet*)owner; @@ -80,7 +80,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { }, PNEWTABLET, "Tablet"); - PNEWTABLET->hyprListener_Tip.initCallback(&pDevice->tablet->events.tip, [](void* owner, void* data) { + PNEWTABLET->hyprListener_Tip.initCallback(&wlr_tablet_from_input_device(pDevice)->events.tip, [](void* owner, void* data) { const auto EVENT = (wlr_tablet_tool_tip_event*)data; const auto PTAB = (STablet*)owner; @@ -98,7 +98,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { }, PNEWTABLET, "Tablet"); - PNEWTABLET->hyprListener_Button.initCallback(&pDevice->tablet->events.button, [](void* owner, void* data) { + PNEWTABLET->hyprListener_Button.initCallback(&wlr_tablet_from_input_device(pDevice)->events.button, [](void* owner, void* data) { const auto EVENT = (wlr_tablet_tool_button_event*)data; const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool); @@ -107,7 +107,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { }, PNEWTABLET, "Tablet"); - PNEWTABLET->hyprListener_Proximity.initCallback(&pDevice->tablet->events.proximity, [](void* owner, void* data) { + PNEWTABLET->hyprListener_Proximity.initCallback(&wlr_tablet_from_input_device(pDevice)->events.proximity, [](void* owner, void* data) { const auto EVENT = (wlr_tablet_tool_proximity_event*)data; const auto PTAB = (STablet*)owner; @@ -165,7 +165,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) { PNEWPAD->wlrTabletPadV2 = wlr_tablet_pad_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice); - PNEWPAD->hyprListener_Button.initCallback(&pDevice->tablet_pad->events.button, [](void* owner, void* data) { + PNEWPAD->hyprListener_Button.initCallback(&wlr_tablet_pad_from_input_device(pDevice)->events.button, [](void* owner, void* data) { const auto EVENT = (wlr_tablet_pad_button_event*)data; const auto PPAD = (STabletPad*)owner; @@ -175,7 +175,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) { }, PNEWPAD, "Tablet Pad"); - PNEWPAD->hyprListener_Strip.initCallback(&pDevice->tablet_pad->events.strip, [](void* owner, void* data) { + PNEWPAD->hyprListener_Strip.initCallback(&wlr_tablet_pad_from_input_device(pDevice)->events.strip, [](void* owner, void* data) { const auto EVENT = (wlr_tablet_pad_strip_event*)data; const auto PPAD = (STabletPad*)owner; @@ -184,7 +184,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) { }, PNEWPAD, "Tablet Pad"); - PNEWPAD->hyprListener_Ring.initCallback(&pDevice->tablet_pad->events.strip, [](void* owner, void* data) { + PNEWPAD->hyprListener_Ring.initCallback(&wlr_tablet_pad_from_input_device(pDevice)->events.strip, [](void* owner, void* data) { const auto EVENT = (wlr_tablet_pad_ring_event*)data; const auto PPAD = (STabletPad*)owner; @@ -193,7 +193,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) { }, PNEWPAD, "Tablet Pad"); - PNEWPAD->hyprListener_Attach.initCallback(&pDevice->tablet_pad->events.strip, [](void* owner, void* data) { + PNEWPAD->hyprListener_Attach.initCallback(&wlr_tablet_pad_from_input_device(pDevice)->events.strip, [](void* owner, void* data) { const auto TABLET = (wlr_tablet_tool*)data; const auto PPAD = (STabletPad*)owner; diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 4a5baf50..90b41a4b 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -2,15 +2,14 @@ #include "OpenGL.hpp" bool CFramebuffer::alloc(int w, int h) { - bool firstAlloc = false; - if (m_iFb == (uint32_t)-1) - { + bool firstAlloc = false; + + if (m_iFb == (uint32_t)-1) { firstAlloc = true; glGenFramebuffers(1, &m_iFb); } - if (m_cTex.m_iTexID == 0) - { + if (m_cTex.m_iTexID == 0) { firstAlloc = true; glGenTextures(1, &m_cTex.m_iTexID); glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); @@ -20,13 +19,11 @@ bool CFramebuffer::alloc(int w, int h) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } - if (firstAlloc || m_Size != Vector2D(w, h)) - { + if (firstAlloc || m_Size != Vector2D(w, h)) { glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); - glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0); @@ -37,7 +34,6 @@ bool CFramebuffer::alloc(int w, int h) { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); - glBindTexture(GL_TEXTURE_2D, m_pStencilTex->m_iTexID); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_pStencilTex->m_iTexID, 0); } @@ -78,3 +74,7 @@ void CFramebuffer::release() { m_cTex.m_iTexID = 0; m_iFb = -1; } + +CFramebuffer::~CFramebuffer() { + release(); +} \ No newline at end of file diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index 3d15069d..6af59ca2 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -6,6 +6,8 @@ class CFramebuffer { public: + ~CFramebuffer(); + bool alloc(int w, int h); void bind(); void release(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 793901aa..d60e827e 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -311,21 +311,21 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } -void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha, int round) { +void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha, int round, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTexture(CTexture(tex), pBox, alpha, round); + renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV); } -void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool allowPrimary) { +void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, false, allowPrimary); + renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, false, allowCustomUV); scissor((wlr_box*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool noAA, bool allowPrimary) { +void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool noAA, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); @@ -388,7 +388,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - if (allowPrimary && m_RenderData.renderingPrimarySurface && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) { + if (allowCustomUV && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) { const float verts[] = { m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVTopLeft.y, // top right m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVTopLeft.y, // top left @@ -702,8 +702,6 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { begin(PMONITOR, &fakeDamage, true); - pixman_region32_fini(&fakeDamage); - clear(CColor(0,0,0,0)); // JIC timespec now; @@ -717,7 +715,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { const auto BLURVAL = g_pConfigManager->getInt("decoration:blur"); g_pConfigManager->setInt("decoration:blur", 0); - g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders); + g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL); g_pConfigManager->setInt("decoration:blur", BLURVAL); @@ -742,9 +740,10 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { #else glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb); #endif - end(); + pixman_region32_fini(&fakeDamage); + wlr_output_rollback(PMONITOR->output); } @@ -762,8 +761,6 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) { begin(PMONITOR, &fakeDamage, true); - pixman_region32_fini(&fakeDamage); - const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer]; glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y); @@ -792,6 +789,8 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) { end(); + pixman_region32_fini(&fakeDamage); + wlr_output_rollback(PMONITOR->output); } @@ -915,9 +914,28 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } +void CHyprOpenGLImpl::renderSplash(cairo_t *const CAIRO, cairo_surface_t *const CAIROSURFACE) { + cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + + const auto FONTSIZE = (int)(m_RenderData.pMonitor->vecPixelSize.y / 76); + cairo_set_font_size(CAIRO, FONTSIZE); + + cairo_set_source_rgba(CAIRO, 1.f, 1.f, 1.f, 0.32f); + + cairo_text_extents_t textExtents; + cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents); + + cairo_move_to(CAIRO, m_RenderData.pMonitor->vecPixelSize.x / 2.f - textExtents.width / 2.f, m_RenderData.pMonitor->vecPixelSize.y - textExtents.height - 1); + cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str()); + + cairo_surface_flush(CAIROSURFACE); +} + void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); + static auto *const PNOSPLASH = &g_pConfigManager->getConfigValuePtr("misc:disable_splash_rendering")->intValue; + // release the last tex if exists const auto PTEX = &m_mMonitorBGTextures[pMonitor]; PTEX->destroyTexture(); @@ -926,6 +944,9 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { Debug::log(LOG, "Allocated texture for BGTex"); + // TODO: use relative paths to the installation + // or configure the paths at build time + // check if wallpapers exist if (!std::filesystem::exists("/usr/share/hyprland/wall_8K.png")) return; // the texture will be empty, oh well. We'll clear with a solid color anyways. @@ -949,6 +970,9 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { const auto CAIRO = cairo_create(CAIROSURFACE); + if (!*PNOSPLASH) + renderSplash(CAIRO, CAIROSURFACE); + // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); glBindTexture(GL_TEXTURE_2D, PTEX->m_iTexID); @@ -969,9 +993,12 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { void CHyprOpenGLImpl::clearWithTex() { RASSERT(m_RenderData.pMonitor, "Tried to render BGtex without begin()!"); - wlr_box box = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; + static auto *const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue; - renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &box, 255, 0); + if (!*PRENDERTEX) { + wlr_box box = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; + renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &box, 255, 0); + } } void CHyprOpenGLImpl::destroyMonitorResources(SMonitor* pMonitor) { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 292eba36..84cfcd39 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -6,6 +6,8 @@ #include #include +#include + #include "Shaders.hpp" #include "Shader.hpp" #include "Texture.hpp" @@ -45,7 +47,6 @@ struct SCurrentRenderData { pixman_region32_t* pDamage = nullptr; - bool renderingPrimarySurface = false; Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); }; @@ -60,8 +61,8 @@ public: void renderRect(wlr_box*, const CColor&, int round = 0); void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0); - void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0); - void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowPrimary = false); + void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0, bool allowCustomUV = false); + void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowCustomUV = false); void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0); void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0); void renderBorder(wlr_box*, const CColor&, int round); @@ -121,7 +122,9 @@ private: // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage); - void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowPrimary = false); + void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false); + + void renderSplash(cairo_t *const, cairo_surface_t *const); }; inline std::unique_ptr g_pHyprOpenGL; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index eaa3cd90..d2b5efa9 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -12,22 +12,30 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, RDATA->output, &outputX, &outputY); wlr_box windowBox; - if (RDATA->surface && surface == RDATA->surface) { + if (RDATA->surface && surface == RDATA->surface) windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, RDATA->w, RDATA->h}; - } else { // here we clamp to 2, these might be some tiny specks + else // here we clamp to 2, these might be some tiny specks windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::clamp(surface->current.width, 2, 1337420), std::clamp(surface->current.height, 2, 1337420)}; + + // squish all oversized + if (RDATA->squishOversized) { + if (x + windowBox.width > RDATA->w) + windowBox.width = RDATA->w - x; + if (y + windowBox.height > RDATA->h) + windowBox.height = RDATA->h - y; } + scaleBox(&windowBox, RDATA->output->scale); static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding; - g_pHyprOpenGL->m_RenderData.renderingPrimarySurface = false; - if (RDATA->surface && surface == RDATA->surface) { - g_pHyprOpenGL->m_RenderData.renderingPrimarySurface = true; - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding); + if (RDATA->blur) + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding); + else + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true); if (RDATA->decorate) { auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col(); @@ -35,8 +43,18 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { g_pHyprOpenGL->renderBorder(&windowBox, col, rounding); } } - else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false, false); + else { + if (RDATA->surface && wlr_surface_is_xdg_surface(RDATA->surface)) { + wlr_box geo; + wlr_xdg_surface_get_geometry(wlr_xdg_surface_from_wlr_surface(RDATA->surface), &geo); + + windowBox.x -= geo.x; + windowBox.y -= geo.y; + } + + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false); + } + wlr_surface_send_frame_done(surface, RDATA->when); @@ -54,8 +72,8 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) { return true; const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); - // if not, check if it maybe is active on a different monitor. vvv might be animation in progress - if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))) + // if not, check if it maybe is active on a different monitor. vvv might be animation in progress + if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && PWORKSPACE->m_bForceRendering) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))) return true; if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) @@ -93,7 +111,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor continue; // found it! - renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL); + renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL); pWorkspaceWindow = w.get(); } @@ -103,7 +121,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || !w->m_bCreatedOverFullscreen || !w->m_bIsMapped) continue; - renderWindow(w.get(), pMonitor, time, true); + renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); } // and then special windows @@ -118,7 +136,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor continue; // render the bad boy - renderWindow(w.get(), pMonitor, time, true); + renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); } // and the overlay layers @@ -140,7 +158,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor g_pHyprError->draw(); } -void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* time, bool decorate) { +void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode) { if (pWindow->m_bHidden) return; @@ -160,9 +178,11 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* renderdata.h = std::clamp(pWindow->m_vRealSize.vec().y, (double)5, (double)1337420); // otherwise we'll have issues later with invalid boxes renderdata.dontRound = pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (PWORKSPACE->m_fAlpha.fl() / 255.f); - renderdata.alpha = pWindow->m_bIsFullscreen ? g_pConfigManager->getFloat("decoration:fullscreen_opacity") : pWindow == g_pCompositor->m_pLastWindow ? g_pConfigManager->getFloat("decoration:active_opacity") : g_pConfigManager->getFloat("decoration:inactive_opacity"); + renderdata.alpha = pWindow->m_fActiveInactiveAlpha.fl(); renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true) && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL); renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding; + renderdata.blur = true; // if it shouldn't, it will be ignored later + renderdata.squishOversized = pWindow->m_vRealPosition.isBeingAnimated(); // apply window special data if (pWindow->m_sSpecialRenderData.alphaInactive == -1) @@ -173,37 +193,40 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* g_pHyprOpenGL->m_pCurrentWindow = pWindow; // render window decorations first, if not fullscreen full - if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations) - wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f); - if (!pWindow->m_bIsX11) { + if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_MAIN) { + if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations) + wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f); - // To everyone who makes apps with improperly aligned surfaces, - // For example chromium, or GTK devs who allow shadows on windows, - // a sincere FUCK YOU. + if (!pWindow->m_bIsX11) { + wlr_box geom; + wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom); - wlr_box geom; - wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom); + g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D((double)geom.x / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)geom.y / (double)pWindow->m_uSurface.xdg->surface->current.height); + g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D((double)(geom.width + geom.x) / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)(geom.y + geom.height) / (double)pWindow->m_uSurface.xdg->surface->current.height); - g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D((double)geom.x / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)geom.y / (double)pWindow->m_uSurface.xdg->surface->current.height); - g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D((double)(geom.width + geom.x) / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)(geom.y + geom.height) / (double)pWindow->m_uSurface.xdg->surface->current.height); - - if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) { - // No special UV mods needed + if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) { + // No special UV mods needed + g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); + g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); + } + } else { g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); } + + wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata); + + g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); + g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); } - wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata); - - g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); - g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); - - if (!pWindow->m_bIsX11) { - renderdata.dontRound = false; // restore dontround - renderdata.pMonitor = pMonitor; - wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata); + if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) { + if (!pWindow->m_bIsX11) { + renderdata.dontRound = false; // restore dontround + renderdata.pMonitor = pMonitor; + wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata); + } } g_pHyprOpenGL->m_pCurrentWindow = nullptr; @@ -217,6 +240,11 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, SMonitor* pMonitor, times SRenderData renderdata = {pMonitor->output, time, pLayer->geometry.x, pLayer->geometry.y}; renderdata.fadeAlpha = pLayer->alpha.fl(); + renderdata.blur = pLayer->forceBlur; + renderdata.surface = pLayer->layerSurface->surface; + renderdata.decorate = false; + renderdata.w = pLayer->layerSurface->surface->current.width; + renderdata.h = pLayer->layerSurface->surface->current.height; wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata); } @@ -243,7 +271,25 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { return; } - // Non-floating + // Non-floating main + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) + continue; + + if (w->m_bIsFloating) + continue; // floating are in the second pass + + if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) + continue; // special are in the third pass + + if (!shouldRenderWindow(w.get(), PMONITOR)) + continue; + + // render the bad boy + renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_MAIN); + } + + // Non-floating popup for (auto& w : g_pCompositor->m_vWindows) { if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) continue; @@ -258,7 +304,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { continue; // render the bad boy - renderWindow(w.get(), PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_POPUP); } // floating on top @@ -276,7 +322,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { continue; // render the bad boy - renderWindow(w.get(), PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_ALL); } // and then special @@ -291,7 +337,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { continue; // render the bad boy - renderWindow(w.get(), PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_ALL); } // Render surfaces above windows for monitor @@ -428,7 +474,7 @@ void CHyprRenderer::arrangeLayerArray(SMonitor* pMonitor, const std::listvecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; for (auto& ls : layerSurfaces) { - if (ls->fadingOut || ls->readyToDelete) + if (ls->fadingOut || ls->readyToDelete || !ls->layerSurface) continue; const auto PLAYER = ls->layerSurface; @@ -551,6 +597,11 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) { pixman_region32_init(&damageBox); wlr_surface_get_effective_damage(pSurface, &damageBox); + // schedule frame events + if (!wl_list_empty(&pSurface->current.frame_callback_list)) { + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); + } + if (!pixman_region32_not_empty(&damageBox)) { pixman_region32_fini(&damageBox); return; @@ -799,4 +850,4 @@ void CHyprRenderer::ensureCursorRenderingMode() { bool CHyprRenderer::shouldRenderCursor() { return m_bHasARenderedCursor; -} \ No newline at end of file +} diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index ff9fd4ea..c03c7117 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -17,6 +17,12 @@ enum DAMAGETRACKINGMODES { DAMAGE_TRACKING_FULL }; +enum eRenderPassMode { + RENDER_PASS_ALL = 0, + RENDER_PASS_MAIN, + RENDER_PASS_POPUP +}; + class CHyprRenderer { public: @@ -41,7 +47,7 @@ public: private: void arrangeLayerArray(SMonitor*, const std::list&, bool, wlr_box*); void renderWorkspaceWithFullscreenWindow(SMonitor*, CWorkspace*, timespec*); - void renderWindow(CWindow*, SMonitor*, timespec*, bool); + void renderWindow(CWindow*, SMonitor*, timespec*, bool, eRenderPassMode); void renderLayer(SLayerSurface*, SMonitor*, timespec*); void renderDragIcon(SMonitor*, timespec*); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index abb5d90c..2d46d7a0 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -40,12 +40,8 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { if (g_pLayoutManager->getCurrentLayout()->getLayoutName() != "dwindle") { // ???? - for (auto it = pWindow->m_dWindowDecorations.begin(); it != pWindow->m_dWindowDecorations.end(); it++) { - if (it->get() == this) { - pWindow->m_dWindowDecorations.erase(it); - return; - } - } + m_pWindow->m_vDecosToRemove.push_back(this); + return; } // get the group info @@ -58,12 +54,8 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { if (m_dwGroupMembers.size() == 0) { // remove - for (auto it = pWindow->m_dWindowDecorations.begin(); it != pWindow->m_dWindowDecorations.end(); it++) { - if (it->get() == this) { - pWindow->m_dWindowDecorations.erase(it); - return; - } - } + m_pWindow->m_vDecosToRemove.push_back(this); + return; } } diff --git a/subprojects/wlroots b/subprojects/wlroots index 5c4384a1..b89ed901 160000 --- a/subprojects/wlroots +++ b/subprojects/wlroots @@ -1 +1 @@ -Subproject commit 5c4384a1330faedf975c8b8644881d50390f3613 +Subproject commit b89ed9015c3fbe8d339e9d65cf70fdca6e5645bc