diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 98473496..073333bc 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,9 @@ -Describe your PR, what does it fix/add? +#### Describe your PR, what does it fix/add? -Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.) +#### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.) -Is it ready for merging, or does it need work? +#### Is it ready for merging, or does it need work? diff --git a/CMakeLists.txt b/CMakeLists.txt index 44246e7e..90a23020 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ 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(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing) find_package(Threads REQUIRED) @@ -61,7 +62,7 @@ IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Configuring Hyprland in Debug with CMake!") add_definitions( -DHYPRLAND_DEBUG ) ELSE() - # add_compile_options(-O3) # may crash for some + add_compile_options( -O3 ) message(STATUS "Configuring Hyprland in Release with CMake!") ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) diff --git a/Makefile b/Makefile index bb753451..227d340f 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ clear: rm -rf build rm -f *.o *-protocol.h *-protocol.c rm -f ./hyprctl/hyprctl - rm -rf ./wlroots/build + rm -rf ./subprojects/wlroots/build all: make config @@ -107,6 +107,10 @@ 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 all mkdir -p ${PREFIX}/share/wayland-sessions cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions/ @@ -118,6 +122,13 @@ 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 @@ -126,13 +137,16 @@ uninstall: 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 -config: - make protocols - +fixwlr: sed -i -E 's/(soversion = 11)([^032]|$$)/soversion = 11032/g' subprojects/wlroots/meson.build rm -rf ./subprojects/wlroots/build +config: + make protocols + + make fixwlr + cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release cd subprojects/wlroots && ninja -C build/ diff --git a/flake.lock b/flake.lock index 71e49721..2b1f3cec 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1655807518, - "narHash": "sha256-5YV29Ry/DpAJc/0Hc/+ISVBAjwHpJvAkeKkcUG5lWsc=", + "lastModified": 1656239181, + "narHash": "sha256-wW1xRFBn376yGloXZ4QzBE4hjipMawpV18Lshd9QSPw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a72d7811be1162dd6804c4e36e5402d76fb6e921", + "rev": "f2537a505d45c31fe5d9c27ea9829b6f4c4e6ac5", "type": "github" }, "original": { @@ -26,11 +26,11 @@ "flake": false, "locked": { "host": "gitlab.freedesktop.org", - "lastModified": 1654618691, - "narHash": "sha256-8y3u8CoigjoZOVbA2wCWBHlDNEakv0AVxU46/cOC00s=", + "lastModified": 1655824477, + "narHash": "sha256-1kskHOLsnisR3kqIL5IHrQbQG/4xoXxeEf1ExMV6/RU=", "owner": "wlroots", "repo": "wlroots", - "rev": "b89ed9015c3fbe8d339e9d65cf70fdca6e5645bc", + "rev": "5c4384a1330faedf975c8b8644881d50390f3613", "type": "gitlab" }, "original": { diff --git a/flake.nix b/flake.nix index aff05d7f..b1f621fc 100644 --- a/flake.nix +++ b/flake.nix @@ -32,9 +32,13 @@ src = inputs.wlroots; }); hyprland = prev.callPackage ./nix/default.nix { - version = "0.6.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")); + version = "0.6.2beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")); wlroots = wlroots-hyprland; }; + hyprland-debug = hyprland.override {debug = true;}; + waybar-hyprland = prev.waybar.overrideAttrs (oldAttrs: { + mesonFlags = oldAttrs.mesonFlags ++ ["-Dexperimental=true"]; + }); }; packages = genSystems (system: diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index f60fb600..a1a1122d 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -26,6 +26,8 @@ const std::string USAGE = R"#(usage: hyprctl [command] [(opt)args] dispatch keyword version + kill + hyprpaper reload)#"; void request(std::string arg) { @@ -74,7 +76,65 @@ void request(std::string arg) { char buffer[8192] = {0}; - sizeWritten = read(SERVERSOCKET,buffer, 8192); + sizeWritten = read(SERVERSOCKET, buffer, 8192); + + if (sizeWritten < 0) { + std::cout << "Couldn't read (5)"; + return; + } + + close(SERVERSOCKET); + + std::cout << std::string(buffer); +} + +void requestHyprpaper(std::string arg) { + const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); + + if (SERVERSOCKET < 0) { + std::cout << "Couldn't open a socket (1)"; + return; + } + + const auto SERVER = gethostbyname("localhost"); + + if (!SERVER) { + std::cout << "Couldn't get host (2)"; + return; + } + + // get the instance signature + auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE"); + + if (!instanceSig) { + std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)"; + return; + } + + std::string instanceSigStr = std::string(instanceSig); + + sockaddr_un serverAddress = {0}; + serverAddress.sun_family = AF_UNIX; + + std::string socketPath = "/tmp/hypr/" + instanceSigStr + "/.hyprpaper.sock"; + + strcpy(serverAddress.sun_path, socketPath.c_str()); + + if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { + std::cout << "Couldn't connect to " << socketPath << ". (3)"; + return; + } + + auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length()); + + if (sizeWritten < 0) { + std::cout << "Couldn't write (4)"; + return; + } + + char buffer[8192] = {0}; + + sizeWritten = read(SERVERSOCKET, buffer, 8192); if (sizeWritten < 0) { std::cout << "Couldn't read (5)"; @@ -109,6 +169,17 @@ void keywordRequest(int argc, char** argv) { request(rq); } +void hyprpaperRequest(int argc, char** argv) { + if (argc < 4) { + std::cout << "hyprpaper requires 2 params"; + return; + } + + std::string rq = std::string(argv[2]) + " " + std::string(argv[3]); + + requestHyprpaper(rq); +} + void batchRequest(int argc, char** argv) { std::string rq = "[[BATCH]]" + std::string(argv[2]); @@ -129,10 +200,12 @@ int main(int argc, char** argv) { 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()); else { diff --git a/meson.build b/meson.build index 7c075e4e..00628761 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,15 @@ project('Hyprland', 'cpp', 'c', - version : '0.6.0beta', - default_options : ['warning_level=3', 'cpp_std=c++20', 'default_library=static']) + version : '0.6.2beta', + default_options : ['warning_level=2', 'cpp_std=c++20', 'default_library=static', 'optimization=3']) + +add_project_arguments( + [ + '-Wno-unused-parameter', + '-Wno-unused-value', + '-Wno-missing-field-initializers', + '-Wno-narrowing', + ], + language: 'cpp') wlroots = subproject('wlroots', default_options: ['examples=false']) have_xwlr = wlroots.get_variable('features').get('xwayland') diff --git a/nix/default.nix b/nix/default.nix index 18570f12..495345fd 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -20,9 +20,10 @@ xwayland, enableXWayland ? true, version ? "git", + debug ? false, }: stdenv.mkDerivation { - pname = "hyprland"; + pname = "hyprland" + lib.optionalString debug "-debug"; inherit version; src = ../.; @@ -48,7 +49,10 @@ stdenv.mkDerivation { ] ++ lib.optional enableXWayland xwayland; - mesonBuildType = "release"; + mesonBuildType = + if debug + then "debug" + else "release"; mesonFlags = lib.optional (!enableXWayland) "-DNO_XWAYLAND=true"; diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a3fd3b93..0d8698a6 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -3,6 +3,11 @@ CCompositor::CCompositor() { m_szInstanceSignature = GIT_COMMIT_HASH + std::string("_") + std::to_string(time(NULL)); + setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true); + + const auto INSTANCEPATH = "/tmp/hypr/" + m_szInstanceSignature; + mkdir(INSTANCEPATH.c_str(), S_IRWXU | S_IRWXG); + Debug::init(m_szInstanceSignature); Debug::log(LOG, "Instance Signature: %s", m_szInstanceSignature.c_str()); @@ -17,11 +22,6 @@ 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"); - setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true); - - const auto INSTANCEPATH = "/tmp/hypr/" + m_szInstanceSignature; - mkdir(INSTANCEPATH.c_str(), S_IRWXU | S_IRWXG); - m_sWLDisplay = wl_display_create(); m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay); @@ -121,6 +121,11 @@ CCompositor::CCompositor() { m_sWLRToplevelMgr = wlr_foreign_toplevel_manager_v1_create(m_sWLDisplay); m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay); + + m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay); + + wlr_xdg_foreign_v1_create(m_sWLDisplay, m_sWLRForeignRegistry); + wlr_xdg_foreign_v2_create(m_sWLDisplay, m_sWLRForeignRegistry); } CCompositor::~CCompositor() { @@ -167,8 +172,8 @@ void CCompositor::cleanupExit() { m_pLastFocus = nullptr; m_pLastWindow = nullptr; - m_lWorkspaces.clear(); - m_lWindows.clear(); + m_vWorkspaces.clear(); + m_vWindows.clear(); if (g_pXWaylandManager->m_sWLRXWayland) { wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland); @@ -264,9 +269,9 @@ void CCompositor::startCompositor() { } SMonitor* CCompositor::getMonitorFromID(const int& id) { - for (auto& m : m_lMonitors) { - if (m.ID == (uint64_t)id) { - return &m; + for (auto& m : m_vMonitors) { + if (m->ID == (uint64_t)id) { + return m.get(); } } @@ -274,9 +279,9 @@ SMonitor* CCompositor::getMonitorFromID(const int& id) { } SMonitor* CCompositor::getMonitorFromName(const std::string& name) { - for (auto& m : m_lMonitors) { - if (m.szName == name) { - return &m; + for (auto& m : m_vMonitors) { + if (m->szName == name) { + return m.get(); } } @@ -296,18 +301,18 @@ SMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { float bestDistance = 0.f; SMonitor* pBestMon = nullptr; - for (auto& m : m_lMonitors) { - float dist = vecToRectDistanceSquared(point, m.vecPosition, m.vecPosition + m.vecSize); + for (auto& m : m_vMonitors) { + float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize); if (dist < bestDistance || !pBestMon) { bestDistance = dist; - pBestMon = &m; + pBestMon = m.get(); } } if (!pBestMon) { // ????? Debug::log(WARN, "getMonitorFromVector no close mon???"); - return &m_lMonitors.front(); + return m_vMonitors.front().get(); } return pBestMon; @@ -317,13 +322,35 @@ SMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { } void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) { - if (windowExists(pWindow) && !pWindow->m_bFadingOut) - m_lWindows.remove(*pWindow); + if (windowExists(pWindow) && !pWindow->m_bFadingOut){ + if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { + m_dUnmanagedX11Windows.erase(std::remove_if(m_dUnmanagedX11Windows.begin(), m_dUnmanagedX11Windows.end(), [&](std::unique_ptr& el) { return el.get() == pWindow; })); + } + + // if X11, also check its children + // and delete any needed + if (pWindow->m_bIsX11) { + for (auto& w : m_vWindows) { + if (!w->m_bIsX11) + continue; + + if (w->m_pX11Parent == pWindow) + m_vWindows.erase(std::remove_if(m_vWindows.begin(), m_vWindows.end(), [&](std::unique_ptr& el) { return el.get() == w.get(); })); + } + + for (auto& w : m_dUnmanagedX11Windows) { + if (w->m_pX11Parent == pWindow) + m_dUnmanagedX11Windows.erase(std::remove_if(m_dUnmanagedX11Windows.begin(), m_dUnmanagedX11Windows.end(), [&](std::unique_ptr& el) { return el.get() == w.get(); })); + } + } + + m_vWindows.erase(std::remove_if(m_vWindows.begin(), m_vWindows.end(), [&](std::unique_ptr& el) { return el.get() == pWindow; })); + } } bool CCompositor::windowExists(CWindow* pWindow) { - for (auto& w : m_lWindows) { - if (&w == pWindow) + for (auto& w : m_vWindows) { + if (w.get() == pWindow) return true; } @@ -334,24 +361,24 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) { const auto PMONITOR = getMonitorFromVector(pos); if (PMONITOR->specialWorkspaceOpen) { - for (auto& w : m_lWindows) { - 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) - return &w; + 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) + return w.get(); } } - // 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_lWindows.rbegin(); w != m_lWindows.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 (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) - return &(*w); + // first loop over floating cuz they're above, m_vWindows 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 (wlr_box_contains_point(&box, pos.x, pos.y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden) + return w->get(); } - for (auto& w : m_lWindows) { - wlr_box box = {w.m_vRealPosition.vec().x, w.m_vRealPosition.vec().y, w.m_vRealSize.vec().x, w.m_vRealSize.vec().y}; - if (wlr_box_contains_point(&box, pos.x, pos.y) && w.m_bIsMapped && !w.m_bIsFloating && PMONITOR->activeWorkspace == w.m_iWorkspaceID && !w.m_bHidden) - return &w; + 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 (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->m_bHidden) + return w.get(); } return nullptr; @@ -361,17 +388,17 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) { const auto PMONITOR = getMonitorFromVector(pos); if (PMONITOR->specialWorkspaceOpen) { - for (auto& w : m_lWindows) { - 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, pos.x, pos.y) && !w.m_bIsFloating && !w.m_bHidden) - return &w; + 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, pos.x, pos.y) && !w->m_bIsFloating && !w->m_bHidden) + return w.get(); } } - for (auto& w : m_lWindows) { - wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y}; - if (w.m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w.m_iWorkspaceID == PMONITOR->activeWorkspace && !w.m_bIsFloating && !w.m_bHidden) - return &w; + 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_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->m_bHidden) + return w.get(); } return nullptr; @@ -382,24 +409,24 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) { // special workspace if (PMONITOR->specialWorkspaceOpen) { - for (auto& w : m_lWindows) { - 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) - return &w; + 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) + return w.get(); } } // 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_lWindows.rbegin(); w != m_lWindows.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); + 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(); } - for (auto& w : m_lWindows) { - 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) - return &w; + 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) + return w.get(); } return nullptr; @@ -409,34 +436,34 @@ CWindow* CCompositor::windowFromCursor() { const auto PMONITOR = getMonitorFromCursor(); if (PMONITOR->specialWorkspaceOpen) { - for (auto& w : m_lWindows) { - 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) - return &w; + 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) + return w.get(); } } // 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_lWindows.rbegin(); w != m_lWindows.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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID)) - return &(*w); + 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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID)) + return w->get(); } - for (auto& w : m_lWindows) { - wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y}; - if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w.m_bIsMapped && w.m_iWorkspaceID == PMONITOR->activeWorkspace) - return &w; + 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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace) + return w.get(); } return nullptr; } CWindow* CCompositor::windowFloatingFromCursor() { - for (auto w = m_lWindows.rbegin(); w != m_lWindows.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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) - return &(*w); + 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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden) + return w->get(); } return nullptr; @@ -475,9 +502,9 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW } SMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) { - for (auto& m : m_lMonitors) { - if (m.output == out) { - return &m; + for (auto& m : m_vMonitors) { + if (m->output == out) { + return m.get(); } } @@ -586,59 +613,58 @@ bool CCompositor::windowValidMapped(CWindow* pWindow) { if (pWindow->m_bHidden) return false; - if (!g_pXWaylandManager->getWindowSurface(pWindow)) - return false; - return true; } CWindow* CCompositor::getWindowForPopup(wlr_xdg_popup* popup) { - for (auto& p : m_lXDGPopups) { - if (p.popup == popup) - return p.parentWindow; + for (auto& p : m_vXDGPopups) { + if (p->popup == popup) + return p->parentWindow; } return nullptr; } -wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::list* layerSurfaces, Vector2D* sCoords) { +wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::list* layerSurfaces, Vector2D* sCoords, SLayerSurface** ppLayerSurfaceFound) { for (auto it = layerSurfaces->rbegin(); it != layerSurfaces->rend(); it++) { if ((*it)->fadingOut || !(*it)->layerSurface || ((*it)->layerSurface && !(*it)->layerSurface->mapped)) continue; const auto SURFACEAT = wlr_layer_surface_v1_surface_at((*it)->layerSurface, pos.x - (*it)->geometry.x, pos.y - (*it)->geometry.y, &sCoords->x, &sCoords->y); - if (SURFACEAT) + if (SURFACEAT) { + *ppLayerSurfaceFound = *it; return SURFACEAT; + } } return nullptr; } CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) { - for (auto& w : m_lWindows) { - if (g_pXWaylandManager->getWindowSurface(&w) == pSurface) - return &w; + for (auto& w : m_vWindows) { + if (g_pXWaylandManager->getWindowSurface(w.get()) == pSurface) + return w.get(); } return nullptr; } CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { - for (auto& w : m_lWindows) { - if (w.m_iWorkspaceID == ID && w.m_bIsFullscreen) - return &w; + for (auto& w : m_vWindows) { + if (w->m_iWorkspaceID == ID && w->m_bIsFullscreen) + return w.get(); } return nullptr; } bool CCompositor::isWorkspaceVisible(const int& w) { - for (auto& m : m_lMonitors) { - if (m.activeWorkspace == w) + for (auto& m : m_vMonitors) { + if (m->activeWorkspace == w) return true; - if (m.specialWorkspaceOpen && w == SPECIAL_WORKSPACE_ID) + if (m->specialWorkspaceOpen && w == SPECIAL_WORKSPACE_ID) return true; } @@ -646,34 +672,42 @@ bool CCompositor::isWorkspaceVisible(const int& w) { } CWorkspace* CCompositor::getWorkspaceByID(const int& id) { - for (auto& w : m_lWorkspaces) { - if (w.m_iID == id) - return &w; + for (auto& w : m_vWorkspaces) { + if (w->m_iID == id) + return w.get(); } return nullptr; } void CCompositor::sanityCheckWorkspaces() { - for (auto it = m_lWorkspaces.begin(); it != m_lWorkspaces.end(); ++it) { - if ((getWindowsOnWorkspace(it->m_iID) == 0 && !isWorkspaceVisible(it->m_iID))) { - it = m_lWorkspaces.erase(it); + for (auto it = m_vWorkspaces.begin(); it != m_vWorkspaces.end(); ++it) { + const auto WINDOWSONWORKSPACE = getWindowsOnWorkspace((*it)->m_iID); + + if ((WINDOWSONWORKSPACE == 0 && !isWorkspaceVisible((*it)->m_iID))) { + it = m_vWorkspaces.erase(it); + + if (it == m_vWorkspaces.end()) + break; } - if (it->m_iID == SPECIAL_WORKSPACE_ID && getWindowsOnWorkspace(it->m_iID) == 0) { - for (auto& m : m_lMonitors) { - m.specialWorkspaceOpen = false; + if ((*it)->m_iID == SPECIAL_WORKSPACE_ID && WINDOWSONWORKSPACE == 0) { + for (auto& m : m_vMonitors) { + m->specialWorkspaceOpen = false; } - it = m_lWorkspaces.erase(it); + it = m_vWorkspaces.erase(it); + + if (it == m_vWorkspaces.end()) + break; } } } int CCompositor::getWindowsOnWorkspace(const int& id) { int no = 0; - for (auto& w : m_lWindows) { - if (w.m_iWorkspaceID == id && w.m_bIsMapped) + for (auto& w : m_vWindows) { + if (w->m_iWorkspaceID == id && w->m_bIsMapped) no++; } @@ -681,9 +715,9 @@ int CCompositor::getWindowsOnWorkspace(const int& id) { } CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) { - for (auto& w : m_lWindows) { - if (w.m_iWorkspaceID == id) - return &w; + for (auto& w : m_vWindows) { + if (w->m_iWorkspaceID == id) + return w.get(); } return nullptr; @@ -697,16 +731,16 @@ void CCompositor::fixXWaylandWindowsOnWorkspace(const int& id) { if (!PWORKSPACE) return; - for (auto& w : m_lWindows) { - if (w.m_iWorkspaceID == id) { + for (auto& w : m_vWindows) { + if (w->m_iWorkspaceID == id) { // moveXWaylandWindow only moves XWayland windows // so there is no need to check here // if the window is XWayland or not. - if (ISVISIBLE && (!PWORKSPACE->m_bHasFullscreenWindow || w.m_bIsFullscreen)) - g_pXWaylandManager->moveXWaylandWindow(&w, w.m_vRealPosition.vec()); + if (ISVISIBLE && (!PWORKSPACE->m_bHasFullscreenWindow || w->m_bIsFullscreen)) + g_pXWaylandManager->moveXWaylandWindow(w.get(), w->m_vRealPosition.vec()); else - g_pXWaylandManager->moveXWaylandWindow(&w, Vector2D(42069,42069)); + g_pXWaylandManager->moveXWaylandWindow(w.get(), Vector2D(42069,42069)); } } } @@ -731,37 +765,37 @@ void CCompositor::moveWindowToTop(CWindow* pWindow) { if (!windowValidMapped(pWindow)) return; - for (auto it = m_lWindows.begin(); it != m_lWindows.end(); ++it) { - if (&(*it) == pWindow) { - m_lWindows.splice(m_lWindows.end(), m_lWindows, it); + for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) { + if (it->get() == pWindow) { + std::rotate(it, it + 1, m_vWindows.end()); break; } } } void CCompositor::cleanupFadingOut() { - for (auto& w : m_lWindowsFadingOut) { + for (auto& w : m_vWindowsFadingOut) { bool valid = windowExists(w); - + if (!valid || !w->m_bFadingOut || w->m_fAlpha.fl() == 0.f) { if (valid && !w->m_bReadyToDelete) continue; g_pHyprOpenGL->m_mWindowFramebuffers[w].release(); g_pHyprOpenGL->m_mWindowFramebuffers.erase(w); - m_lWindows.remove(*w); - m_lWindowsFadingOut.remove(w); + removeWindowFromVectorSafe(w); + m_vWindowsFadingOut.erase(std::remove(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), w)); Debug::log(LOG, "Cleanup: destroyed a window"); return; } } - for (auto& ls : m_lSurfacesFadingOut) { + for (auto& ls : m_vSurfacesFadingOut) { if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) { - for (auto& m : m_lMonitors) { - for (auto& lsl : m.m_aLayerSurfaceLists) { + for (auto& m : m_vMonitors) { + for (auto& lsl : m->m_aLayerSurfaceLists) { lsl.remove(ls); } } @@ -770,7 +804,7 @@ void CCompositor::cleanupFadingOut() { g_pHyprOpenGL->m_mLayerFramebuffers.erase(ls); delete ls; - m_lSurfacesFadingOut.remove(ls); + m_vSurfacesFadingOut.erase(std::remove(m_vSurfacesFadingOut.begin(), m_vSurfacesFadingOut.end(), ls)); Debug::log(LOG, "Cleanup: destroyed a layersurface"); @@ -789,11 +823,11 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { auto longestIntersect = -1; CWindow* longestIntersectWindow = nullptr; - for (auto& w : m_lWindows) { - if (&w == pWindow || !windowValidMapped(&w) || w.m_bIsFloating || !isWorkspaceVisible(w.m_iWorkspaceID)) + for (auto& w : m_vWindows) { + if (w.get() == pWindow || !w->m_bIsMapped || w->m_bHidden || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID)) continue; - const auto BWINDOWIDEALBB = w.getWindowIdealBoundingBoxIgnoreReserved(); + const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y); const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height); @@ -804,7 +838,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { const auto INTERSECTLEN = std::max((double)0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectWindow = &w; + longestIntersectWindow = w.get(); } } break; @@ -813,7 +847,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { const auto INTERSECTLEN = std::max((double)0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectWindow = &w; + longestIntersectWindow = w.get(); } } break; @@ -823,7 +857,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { const auto INTERSECTLEN = std::max((double)0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectWindow = &w; + longestIntersectWindow = w.get(); } } break; @@ -833,7 +867,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { const auto INTERSECTLEN = std::max((double)0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectWindow = &w; + longestIntersectWindow = w.get(); } } break; @@ -847,30 +881,30 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { } void CCompositor::deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude) { - for (auto& w : m_lWorkspaces) { - if (w.m_pWlrHandle && w.m_pWlrHandle != exclude) - w.setActive(false); + for (auto& w : m_vWorkspaces) { + if (w->m_pWlrHandle && w->m_pWlrHandle != exclude) + w->setActive(false); } } CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow) { bool gotToWindow = false; - for (auto& w : m_lWindows) { - if (&w != pWindow && !gotToWindow) + for (auto& w : m_vWindows) { + if (w.get() != pWindow && !gotToWindow) continue; - if (&w == pWindow) { + if (w.get() == pWindow) { gotToWindow = true; continue; } - if (w.m_iWorkspaceID == pWindow->m_iWorkspaceID && windowValidMapped(&w)) - return &w; + if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->m_bHidden) + return w.get(); } - for (auto& w : m_lWindows) { - if (&w != pWindow && w.m_iWorkspaceID == pWindow->m_iWorkspaceID && windowValidMapped(&w)) - return &w; + for (auto& w : m_vWindows) { + if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->m_bHidden) + return w.get(); } return nullptr; @@ -878,18 +912,18 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow) { int CCompositor::getNextAvailableNamedWorkspace() { int lowest = -1337 + 1; - for (auto& w : m_lWorkspaces) { - if (w.m_iID < -1 && w.m_iID < lowest) - lowest = w.m_iID; + for (auto& w : m_vWorkspaces) { + if (w->m_iID < -1 && w->m_iID < lowest) + lowest = w->m_iID; } return lowest - 1; } CWorkspace* CCompositor::getWorkspaceByName(const std::string& name) { - for (auto& w : m_lWorkspaces) { - if (w.m_szName == name) - return &w; + for (auto& w : m_vWorkspaces) { + if (w->m_szName == name) + return w.get(); } return nullptr; @@ -911,8 +945,8 @@ CWorkspace* CCompositor::getWorkspaceByString(const std::string& str) { } bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) { - for (auto& m : m_lMonitors) { - if (VECINRECT(point, m.vecPosition.x, m.vecPosition.y, m.vecSize.x + m.vecPosition.x, m.vecSize.y + m.vecPosition.y)) + for (auto& m : m_vMonitors) { + if (VECINRECT(point, m->vecPosition.x, m->vecPosition.y, m->vecSize.x + m->vecPosition.x, m->vecSize.y + m->vecPosition.y)) return true; } @@ -925,12 +959,12 @@ CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) { const auto PSURFACE = pMouse->currentConstraint->surface; - for (auto& w : m_lWindows) { - if (PSURFACE == g_pXWaylandManager->getWindowSurface(&w)) { - if (!w.m_bIsX11 && !windowValidMapped(&w)) + for (auto& w : m_vWindows) { + if (PSURFACE == g_pXWaylandManager->getWindowSurface(w.get())) { + if (!w->m_bIsX11 && w->m_bIsMapped && !w->m_bHidden) continue; - return &w; + return w.get(); } } @@ -944,19 +978,19 @@ SMonitor* CCompositor::getMonitorInDirection(const char& dir) { auto longestIntersect = -1; SMonitor* longestIntersectMonitor = nullptr; - for (auto& m : m_lMonitors) { - if (&m == m_pLastMonitor) + for (auto& m : m_vMonitors) { + if (m.get() == m_pLastMonitor) continue; - const auto POSB = m.vecPosition; - const auto SIZEB = m.vecSize; + const auto POSB = m->vecPosition; + const auto SIZEB = m->vecSize; switch (dir) { case 'l': if (STICKS(POSA.x, POSB.x + SIZEB.x)) { const auto INTERSECTLEN = std::max((double)0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectMonitor = &m; + longestIntersectMonitor = m.get(); } } break; @@ -965,7 +999,7 @@ SMonitor* CCompositor::getMonitorInDirection(const char& dir) { const auto INTERSECTLEN = std::max((double)0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectMonitor = &m; + longestIntersectMonitor = m.get(); } } break; @@ -975,7 +1009,7 @@ SMonitor* CCompositor::getMonitorInDirection(const char& dir) { const auto INTERSECTLEN = std::max((double)0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectMonitor = &m; + longestIntersectMonitor = m.get(); } } break; @@ -985,7 +1019,7 @@ SMonitor* CCompositor::getMonitorInDirection(const char& dir) { const auto INTERSECTLEN = std::max((double)0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectMonitor = &m; + longestIntersectMonitor = m.get(); } } break; @@ -999,11 +1033,11 @@ SMonitor* CCompositor::getMonitorInDirection(const char& dir) { } void CCompositor::updateAllWindowsBorders() { - for (auto& w : m_lWindows) { - if (!w.m_bIsMapped) + for (auto& w : m_vWindows) { + if (!w->m_bIsMapped) continue; - updateWindowBorderColor(&w); + updateWindowBorderColor(w.get()); } } @@ -1028,9 +1062,9 @@ void CCompositor::moveWindowToWorkspace(CWindow* pWindow, const std::string& wor int CCompositor::getNextAvailableMonitorID() { int64_t topID = -1; - for (auto& m : m_lMonitors) { - if ((int64_t)m.ID > topID) - topID = m.ID; + for (auto& m : m_vMonitors) { + if ((int64_t)m->ID > topID) + topID = m->ID; } return topID + 1; @@ -1051,9 +1085,9 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, SMonitor* pMoni // fix old mon int nextWorkspaceOnMonitorID = -1; - for (auto& w : m_lWorkspaces) { - if (w.m_iMonitorID == POLDMON->ID && w.m_iID != pWorkspace->m_iID) { - nextWorkspaceOnMonitorID = w.m_iID; + for (auto& w : m_vWorkspaces) { + if (w->m_iMonitorID == POLDMON->ID && w->m_iID != pWorkspace->m_iID) { + nextWorkspaceOnMonitorID = w->m_iID; break; } } @@ -1077,9 +1111,9 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, SMonitor* pMoni pWorkspace->m_iMonitorID = pMonitor->ID; pWorkspace->moveToMonitor(pMonitor->ID); - for (auto& w : m_lWindows) { - if (w.m_iWorkspaceID == pWorkspace->m_iID) - w.m_iMonitorID = pMonitor->ID; + for (auto& w : m_vWindows) { + if (w->m_iWorkspaceID == pWorkspace->m_iID) + w->m_iMonitorID = pMonitor->ID; } if (SWITCHINGISACTIVE) { // if it was active, preserve its' status. If it wasn't, don't. @@ -1106,12 +1140,12 @@ bool CCompositor::workspaceIDOutOfBounds(const int& id) { int lowestID = 99999; int highestID = -99999; - for (auto& w : m_lWorkspaces) { - if (w.m_iID < lowestID) - lowestID = w.m_iID; + for (auto& w : m_vWorkspaces) { + if (w->m_iID < lowestID) + lowestID = w->m_iID; - if (w.m_iID > highestID) - highestID = w.m_iID; + if (w->m_iID > highestID) + highestID = w->m_iID; } return std::clamp(id, lowestID, highestID) != id; @@ -1125,8 +1159,33 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL); // make all windows on the same workspace under the fullscreen window - for (auto& w : g_pCompositor->m_lWindows) { - if (w.m_iWorkspaceID == pWindow->m_iWorkspaceID) - w.m_bCreatedOverFullscreen = false; + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID) + w->m_bCreatedOverFullscreen = false; } +} + +void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) { + for (auto it = m_dUnmanagedX11Windows.begin(); it != m_dUnmanagedX11Windows.end(); it++) { + if (it->get() == pWindow) { + m_vWindows.emplace_back(std::move(*it)); + m_dUnmanagedX11Windows.erase(it); + return; + } + } +} + +CWindow* CCompositor::getX11Parent(CWindow* pWindow) { + if (!pWindow->m_bIsX11) + return nullptr; + + for (auto& w : m_vWindows) { + if (!w->m_bIsX11) + continue; + + if (w->m_uSurface.xwayland == pWindow->m_uSurface.xwayland->parent) + return w.get(); + } + + return nullptr; } \ No newline at end of file diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 16632006..7ad3b7f8 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -60,19 +60,21 @@ public: wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr; wlr_foreign_toplevel_manager_v1* m_sWLRToplevelMgr; wlr_tablet_manager_v2* m_sWLRTabletManager; + wlr_xdg_foreign_registry* m_sWLRForeignRegistry; // ------------------------------------------------- // const char* m_szWLDisplaySocket; std::string m_szInstanceSignature = ""; - std::list m_lMonitors; - std::list m_lWindows; - std::list m_lXDGPopups; - std::list m_lWorkspaces; - std::list m_lSubsurfaces; - std::list m_lWindowsFadingOut; - std::list m_lSurfacesFadingOut; + std::vector> m_vMonitors; + std::vector> m_vWindows; + std::deque> m_dUnmanagedX11Windows; + std::vector> m_vXDGPopups; + std::vector> m_vWorkspaces; + std::vector> m_vSubsurfaces; + std::vector m_vWindowsFadingOut; + std::vector m_vSurfacesFadingOut; void startCompositor(); void cleanupExit(); @@ -99,7 +101,7 @@ public: CWindow* vectorToWindow(const Vector2D&); CWindow* vectorToWindowIdeal(const Vector2D&); CWindow* vectorToWindowTiled(const Vector2D&); - wlr_surface* vectorToLayerSurface(const Vector2D&, std::list*, Vector2D*); + wlr_surface* vectorToLayerSurface(const Vector2D&, std::list*, Vector2D*, SLayerSurface**); wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl); CWindow* windowFromCursor(); CWindow* windowFloatingFromCursor(); @@ -133,6 +135,8 @@ public: void moveWorkspaceToMonitor(CWorkspace*, SMonitor*); bool workspaceIDOutOfBounds(const int&); void setWindowFullscreen(CWindow*, bool, eFullscreenMode); + void moveUnmanagedX11ToWindows(CWindow*); + CWindow* getX11Parent(CWindow*); private: void initAllSignals(); diff --git a/src/Window.cpp b/src/Window.cpp index fbd06417..fc09b330 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -72,4 +72,21 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() { } return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y}; -} \ No newline at end of file +} + +void CWindow::updateWindowDecos() { + for (auto& wd : m_dWindowDecorations) + wd->updateWindow(this); +} + +pid_t CWindow::getPID() { + pid_t PID = -1; + if (!m_bIsX11) { + const auto CLIENT = wl_resource_get_client(m_uSurface.xdg->resource); + wl_client_get_credentials(CLIENT, &PID, nullptr, nullptr); + } else { + PID = m_uSurface.xwayland->pid; + } + + return PID; +} diff --git a/src/Window.hpp b/src/Window.hpp index 9f92432a..ca6bcbf6 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -67,6 +67,7 @@ public: // XWayland stuff bool m_bIsX11 = false; bool m_bMappedX11 = false; + CWindow* m_pX11Parent = nullptr; uint64_t m_iX11Type = 0; bool m_bIsModal = false; bool m_bX11DoesntWantBorders = false; @@ -76,6 +77,7 @@ public: // For nofocus bool m_bNoFocus = false; + bool m_bNoInitialFocus = false; SSurfaceTreeNode* m_pSurfaceTree = nullptr; @@ -110,5 +112,7 @@ public: // methods wlr_box getFullWindowBoundingBox(); wlr_box getWindowIdealBoundingBoxIgnoreReserved(); + void updateWindowDecos(); + pid_t getPID(); }; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fb3aae1f..f313b155 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -15,6 +15,8 @@ CConfigManager::CConfigManager() { 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"); configPaths.emplace_back(CONFIGPATH); + + Debug::disableLogs = &configValues["debug:disable_logs"].intValue; } void CConfigManager::setDefaultVars() { @@ -38,6 +40,8 @@ void CConfigManager::setDefaultVars() { configValues["debug:int"].intValue = 0; configValues["debug:log_damage"].intValue = 0; configValues["debug:overlay"].intValue = 0; + configValues["debug:damage_blink"].intValue = 0; + configValues["debug:disable_logs"].intValue = 0; configValues["decoration:rounding"].intValue = 1; configValues["decoration:blur"].intValue = 1; @@ -47,12 +51,13 @@ void CConfigManager::setDefaultVars() { configValues["decoration:active_opacity"].floatValue = 1; configValues["decoration:inactive_opacity"].floatValue = 1; configValues["decoration:fullscreen_opacity"].floatValue = 1; - configValues["decoration:multisample_edges"].intValue = 0; + configValues["decoration:multisample_edges"].intValue = 1; configValues["decoration:no_blur_on_oversized"].intValue = 1; configValues["decoration:drop_shadow"].intValue = 1; configValues["decoration:shadow_range"].intValue = 4; configValues["decoration:shadow_render_power"].intValue = 3; configValues["decoration:shadow_ignore_window"].intValue = 1; + configValues["decoration:shadow_offset"].strValue = "0 0"; configValues["decoration:col.shadow"].intValue = 0xee1a1a1a; configValues["dwindle:pseudotile"].intValue = 0; @@ -103,6 +108,24 @@ void CConfigManager::setDefaultVars() { configValues["autogenerated"].intValue = 0; } +void CConfigManager::setDeviceDefaultVars(const std::string& dev) { + auto& cfgValues = deviceConfigs[dev]; + + cfgValues["kb_layout"].strValue = "us"; + cfgValues["kb_variant"].strValue = STRVAL_EMPTY; + cfgValues["kb_options"].strValue = STRVAL_EMPTY; + cfgValues["kb_rules"].strValue = STRVAL_EMPTY; + cfgValues["kb_model"].strValue = STRVAL_EMPTY; + cfgValues["repeat_rate"].intValue = 25; + cfgValues["repeat_delay"].intValue = 600; + cfgValues["natural_scroll"].intValue = 0; + cfgValues["numlock_by_default"].intValue = 0; + cfgValues["disable_while_typing"].intValue = 1; + cfgValues["clickfinger_behavior"].intValue = 0; + cfgValues["middle_button_emulation"].intValue = 0; + cfgValues["tap-to-click"].intValue = 1; +} + void CConfigManager::init() { loadConfigLoadVars(); @@ -132,33 +155,58 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field."; } - return; + if (COMMAND.find("device:") == 0 /* devices parsed later */) { + parseError = ""; + } else { + return; + } } + SConfigValue* CONFIGENTRY = nullptr; - auto& CONFIGENTRY = configValues.at(COMMAND); - if (CONFIGENTRY.intValue != -1) { + if (COMMAND.find("device:") == 0) { + const auto DEVICE = COMMAND.substr(7).substr(0, COMMAND.find_last_of(':') - 7); + const auto CONFIGVAR = COMMAND.substr(COMMAND.find_last_of(':') + 1); + + if (!deviceConfigExists(DEVICE)) + setDeviceDefaultVars(DEVICE); + + auto it = deviceConfigs.find(DEVICE); + + if (it->second.find(CONFIGVAR) == it->second.end()) { + parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field."; + return; + } + + CONFIGENTRY = &it->second.at(CONFIGVAR); + } else { + CONFIGENTRY = &configValues.at(COMMAND); + } + + CONFIGENTRY->set = true; + + if (CONFIGENTRY->intValue != -1) { try { if (VALUE.find("0x") == 0) { // Values with 0x are hex const auto VALUEWITHOUTHEX = VALUE.substr(2); - CONFIGENTRY.intValue = stol(VALUEWITHOUTHEX, nullptr, 16); + CONFIGENTRY->intValue = stol(VALUEWITHOUTHEX, nullptr, 16); } else - CONFIGENTRY.intValue = stol(VALUE); + CONFIGENTRY->intValue = stol(VALUE); } catch (...) { Debug::log(WARN, "Error reading value of %s", COMMAND.c_str()); parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">."; } - } else if (CONFIGENTRY.floatValue != -1) { + } else if (CONFIGENTRY->floatValue != -1) { try { - CONFIGENTRY.floatValue = stof(VALUE); + CONFIGENTRY->floatValue = stof(VALUE); } catch (...) { Debug::log(WARN, "Error reading value of %s", COMMAND.c_str()); parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">."; } - } else if (CONFIGENTRY.strValue != "") { + } else if (CONFIGENTRY->strValue != "") { try { - CONFIGENTRY.strValue = VALUE; + CONFIGENTRY->strValue = VALUE; } catch (...) { Debug::log(WARN, "Error reading value of %s", COMMAND.c_str()); parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">."; @@ -611,8 +659,8 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: parseError = ""; // invalidate layouts jic - for (auto& m : g_pCompositor->m_lMonitors) - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m.ID); + for (auto& m : g_pCompositor->m_vMonitors) + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); // Update window border colors g_pCompositor->updateAllWindowsBorders(); @@ -704,6 +752,7 @@ void CConfigManager::loadConfigLoadVars() { g_pAnimationManager->removeAllBeziers(); m_mAdditionalReservedAreas.clear(); configDynamicVars.clear(); + deviceConfigs.clear(); // paths configPaths.clear(); @@ -772,8 +821,8 @@ void CConfigManager::loadConfigLoadVars() { ifs.close(); } - for (auto& m : g_pCompositor->m_lMonitors) - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m.ID); + for (auto& m : g_pCompositor->m_vMonitors) + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); // Update the keyboard layout to the cfg'd one if this is not the first launch if (!isFirstLaunch) @@ -806,6 +855,10 @@ void CConfigManager::loadConfigLoadVars() { // Update window border colors g_pCompositor->updateAllWindowsBorders(); + + // Force the compositor to fully re-render all monitors + for (auto& m : g_pCompositor->m_vMonitors) + m->forceFullFrames = 2; } void CConfigManager::tick() { @@ -843,7 +896,7 @@ void CConfigManager::tick() { } std::mutex configmtx; -SConfigValue CConfigManager::getConfigValueSafe(std::string val) { +SConfigValue CConfigManager::getConfigValueSafe(const std::string& val) { std::lock_guard lg(configmtx); SConfigValue copy = configValues[val]; @@ -851,15 +904,38 @@ SConfigValue CConfigManager::getConfigValueSafe(std::string val) { return copy; } -int CConfigManager::getInt(std::string v) { +SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) { + std::lock_guard lg(configmtx); + + const auto it = deviceConfigs.find(dev); + + if (it == deviceConfigs.end()) { + return SConfigValue(); + } + + SConfigValue copy = it->second[val]; + + // fallback if not set explicitly + if (!copy.set) { + for (auto& cv : configValues) { + if (cv.first.find(val) == cv.first.length() - val.length()) { + copy = cv.second; + } + } + } + + return copy; +} + +int CConfigManager::getInt(const std::string& v) { return getConfigValueSafe(v).intValue; } -float CConfigManager::getFloat(std::string v) { +float CConfigManager::getFloat(const std::string& v) { return getConfigValueSafe(v).floatValue; } -std::string CConfigManager::getString(std::string v) { +std::string CConfigManager::getString(const std::string& v) { const auto VAL = getConfigValueSafe(v).strValue; if (VAL == STRVAL_EMPTY) @@ -868,6 +944,23 @@ std::string CConfigManager::getString(std::string v) { return VAL; } +int CConfigManager::getDeviceInt(const std::string& dev, const std::string& v) { + return getConfigValueSafeDevice(dev, v).intValue; +} + +float CConfigManager::getDeviceFloat(const std::string& dev, const std::string& v) { + return getConfigValueSafeDevice(dev, v).floatValue; +} + +std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v) { + const auto VAL = getConfigValueSafeDevice(dev, v).strValue; + + if (VAL == STRVAL_EMPTY) + return ""; + + return VAL; +} + void CConfigManager::setInt(std::string v, int val) { configValues[v].intValue = val; } @@ -964,14 +1057,30 @@ void CConfigManager::dispatchExecOnce() { } void CConfigManager::performMonitorReload() { - for (auto& m : g_pCompositor->m_lMonitors) { - auto rule = getMonitorRuleFor(m.szName); - g_pHyprRenderer->applyMonitorRule(&m, &rule); + + bool overAgain = false; + + for (auto& m : g_pCompositor->m_vMonitors) { + auto rule = getMonitorRuleFor(m->szName); + if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { + overAgain = true; + break; + } } + if (overAgain) + performMonitorReload(); + m_bWantsMonitorReload = false; } SConfigValue* CConfigManager::getConfigValuePtr(std::string val) { return &configValues[val]; } + +bool CConfigManager::deviceConfigExists(const std::string& dev) { + const auto it = deviceConfigs.find(dev); + + return it != deviceConfigs.end(); +} + diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 8c0bd857..bcb2fbe5 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -20,6 +20,8 @@ struct SConfigValue { int64_t intValue = -1; float floatValue = -1; std::string strValue = ""; + + bool set = false; // used for device configs }; struct SMonitorRule { @@ -52,13 +54,18 @@ public: void tick(); void init(); - int getInt(std::string); - float getFloat(std::string); - std::string getString(std::string); + int getInt(const std::string&); + float getFloat(const std::string&); + std::string getString(const std::string&); void setFloat(std::string, float); void setInt(std::string, int); void setString(std::string, std::string); + int getDeviceInt(const std::string&, const std::string&); + float getDeviceFloat(const std::string&, const std::string&); + std::string getDeviceString(const std::string&, const std::string&); + bool deviceConfigExists(const std::string&); + SConfigValue* getConfigValuePtr(std::string); SMonitorRule getMonitorRuleFor(std::string); @@ -81,6 +88,7 @@ private: std::unordered_map configModifyTimes; // stores modify times std::unordered_map configDynamicVars; // stores dynamic vars declared by the user std::unordered_map configValues; + std::unordered_map> deviceConfigs; // stores device configs std::string configCurrentPath; @@ -100,12 +108,15 @@ private: // internal methods void setDefaultVars(); + void setDeviceDefaultVars(const std::string&); void applyUserDefinedVars(std::string&, const size_t); void loadConfigLoadVars(); - SConfigValue getConfigValueSafe(std::string); + SConfigValue getConfigValueSafe(const std::string&); + SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&); void parseLine(std::string&); void configSetValueSafe(const std::string&, const std::string&); + void handleDeviceConfig(const std::string&, const std::string&); void handleRawExec(const std::string&, const std::string&); void handleMonitor(const std::string&, const std::string&); void handleBind(const std::string&, const std::string&, bool locked = false); diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 0395fd30..e8afb296 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -71,6 +71,7 @@ dwindle { # example binds bind=SUPER,Q,exec,kitty +bind=SUPER,RETURN,exec,alacritty bind=SUPER,C,killactive, bind=SUPER,M,exit, bind=SUPER,E,exec,dolphin diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 66a8128d..eb6c085c 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -15,9 +15,9 @@ std::string monitorsRequest() { std::string result = ""; - for (auto& m : g_pCompositor->m_lMonitors) { - 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\n", - m.szName.c_str(), m.ID, (int)m.vecSize.x, (int)m.vecSize.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); + 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); } return result; @@ -25,19 +25,21 @@ std::string monitorsRequest() { std::string clientsRequest() { std::string result = ""; - for (auto& w : g_pCompositor->m_lWindows) { - 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\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).c_str()); + 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 result = ""; - for (auto& w : g_pCompositor->m_lWorkspaces) { + 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); + 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; } @@ -48,17 +50,17 @@ std::string activeWindowRequest() { 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\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()); + 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 result = ""; - for (auto& mon : g_pCompositor->m_lMonitors) { + for (auto& mon : g_pCompositor->m_vMonitors) { result += getFormat("Monitor %s:\n"); int layerLevel = 0; - for (auto& level : mon.m_aLayerSurfaceLists) { + for (auto& level : mon->m_aLayerSurfaceLists) { result += getFormat("\tLayer level %i:\n", layerLevel); for (auto& layer : level) { @@ -173,6 +175,12 @@ std::string reloadRequest() { return "ok"; } +std::string killRequest() { + g_pInputManager->setClickMode(CLICKMODE_KILL); + + return "ok"; +} + std::string getReply(std::string); std::string dispatchBatch(std::string request) { @@ -214,6 +222,8 @@ std::string getReply(std::string request) { return workspacesRequest(); else if (request == "clients") return clientsRequest(); + else if (request == "kill") + return killRequest(); else if (request == "activewindow") return activeWindowRequest(); else if (request == "layers") diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 0eb3ba17..b8d7c32b 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -120,7 +120,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { yOffset += 11; g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); - m_wbLastDrawnBox = {(int)g_pCompositor->m_lMonitors.front().vecPosition.x, (int)g_pCompositor->m_lMonitors.front().vecPosition.y + offset - 1, (int)maxX + 2, yOffset - offset + 2}; + m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset - 1, (int)maxX + 2, yOffset - offset + 2}; g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); return yOffset - offset; @@ -140,7 +140,7 @@ void CHyprDebugOverlay::frameData(SMonitor* pMonitor) { void CHyprDebugOverlay::draw() { - const auto PMONITOR = &g_pCompositor->m_lMonitors.front(); + const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); if (!m_pCairoSurface || !m_pCairo) { m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecSize.x, PMONITOR->vecSize.y); @@ -155,8 +155,8 @@ void CHyprDebugOverlay::draw() { // draw the things int offsetY = 0; - for (auto& m : g_pCompositor->m_lMonitors) { - offsetY += m_mMonitorOverlays[&m].draw(offsetY); + for (auto& m : g_pCompositor->m_vMonitors) { + offsetY += m_mMonitorOverlays[m.get()].draw(offsetY); offsetY += 5; // for padding between mons } diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index a864f0d2..2fa4a127 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -14,6 +14,9 @@ void Debug::init(std::string IS) { void Debug::log(LogLevel level, const char* fmt, ...) { + if (disableLogs && *disableLogs) + return; + // log to a file std::ofstream ofs; ofs.open(logFile, std::ios::out | std::ios::app); diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index 814da421..bde9b820 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -17,4 +17,5 @@ namespace Debug { void log(LogLevel level, const char* fmt, ...); inline std::string logFile; + inline int64_t* disableLogs = nullptr; }; \ No newline at end of file diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index d8b1ff89..04763be1 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -55,17 +55,7 @@ void Events::listener_mouseAxis(wl_listener* listener, void* data) { void Events::listener_requestMouse(wl_listener* listener, void* data) { const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data; - if (!g_pHyprRenderer->shouldRenderCursor()) - return; - - if (!EVENT->surface) { - g_pHyprRenderer->m_bWindowRequestedCursorHide = true; - } else { - g_pHyprRenderer->m_bWindowRequestedCursorHide = false; - } - - if (EVENT->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) - wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, EVENT->surface, EVENT->hotspot_x, EVENT->hotspot_y); + g_pInputManager->processMouseRequest(EVENT); } void Events::listener_newInput(wl_listener* listener, void* data) { diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp index 01cc25cc..773ba909 100644 --- a/src/events/Layers.cpp +++ b/src/events/Layers.cpp @@ -36,7 +36,7 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) { SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].back(); if (!WLRLAYERSURFACE->output) { - WLRLAYERSURFACE->output = g_pCompositor->m_lMonitors.front().output; // TODO: current mon + WLRLAYERSURFACE->output = g_pCompositor->m_vMonitors.front()->output; // TODO: current mon } layerSurface->hyprListener_commitLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.commit, &Events::listener_commitLayerSurface, layerSurface, "layerSurface"); @@ -145,7 +145,7 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) { layersurface->fadingOut = true; - g_pCompositor->m_lSurfacesFadingOut.push_back(layersurface); + g_pCompositor->m_vSurfacesFadingOut.push_back(layersurface); if (layersurface->layerSurface->mapped) layersurface->layerSurface->mapped = false; @@ -179,7 +179,7 @@ void Events::listener_commitLayerSurface(void* owner, void* data) { if (!PMONITOR) return; - wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height}; + wlr_box geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); // fix if it changed its mon @@ -206,6 +206,5 @@ void Events::listener_commitLayerSurface(void* owner, void* data) { layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y); - // TODO: optimize this. This does NOT need to be here but it prevents some issues with full DT. - g_pHyprRenderer->damageMonitor(PMONITOR); + g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y); } \ No newline at end of file diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 9da5f779..11527cee 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -21,24 +21,24 @@ void Events::listener_change(wl_listener* listener, void* data) { // layout got changed, let's update monitors. const auto CONFIG = wlr_output_configuration_v1_create(); - for (auto& m : g_pCompositor->m_lMonitors) { - const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m.output); + for (auto& m : g_pCompositor->m_vMonitors) { + const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output); // TODO: clients off of disabled wlr_box BOX; - wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m.output, &BOX); + wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, &BOX); - //m.vecSize.x = BOX.width; - // m.vecSize.y = BOX.height; - m.vecPosition.x = BOX.x; - m.vecPosition.y = BOX.y; + //m->vecSize.x = BOX.width; + // m->vecSize.y = BOX.height; + m->vecPosition.x = BOX.x; + m->vecPosition.y = BOX.y; - CONFIGHEAD->state.enabled = m.output->enabled; - CONFIGHEAD->state.mode = m.output->current_mode; - CONFIGHEAD->state.x = m.vecPosition.x; - CONFIGHEAD->state.y = m.vecPosition.y; + CONFIGHEAD->state.enabled = m->output->enabled; + CONFIGHEAD->state.mode = m->output->current_mode; + CONFIGHEAD->state.x = m->vecPosition.x; + CONFIGHEAD->state.y = m->vecPosition.y; - wlr_output_set_custom_mode(m.output, m.vecPixelSize.x, m.vecPixelSize.y, (int)(round(m.refreshRate * 1000))); + wlr_output_set_custom_mode(m->output, m->vecPixelSize.x, m->vecPixelSize.y, (int)(round(m->refreshRate * 1000))); } wlr_output_manager_v1_set_configuration(g_pCompositor->m_sWLROutputMgr, CONFIG); @@ -90,8 +90,7 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { newMonitor.vecSize = monitorRule.resolution; newMonitor.refreshRate = monitorRule.refreshRate; - g_pCompositor->m_lMonitors.push_back(newMonitor); - const auto PNEWMONITOR = &g_pCompositor->m_lMonitors.back(); + const auto PNEWMONITOR = g_pCompositor->m_vMonitors.emplace_back(std::make_unique(newMonitor)).get(); PNEWMONITOR->hyprListener_monitorFrame.initCallback(&OUTPUT->events.frame, &Events::listener_monitorFrame, PNEWMONITOR); PNEWMONITOR->hyprListener_monitorDestroy.initCallback(&OUTPUT->events.destroy, &Events::listener_monitorDestroy, PNEWMONITOR); @@ -115,10 +114,10 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { // Workspace std::string newDefaultWorkspaceName = ""; - auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_lWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName); + auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName); if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) { - WORKSPACEID = g_pCompositor->m_lWorkspaces.size() + 1; + WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1; newDefaultWorkspaceName = std::to_string(WORKSPACEID); Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace); @@ -135,13 +134,12 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PNEWMONITOR->ID); PNEWWORKSPACE->startAnim(true,true,true); } else { - PNEWWORKSPACE = &g_pCompositor->m_lWorkspaces.emplace_back(newMonitor.ID); + PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique(newMonitor.ID, newDefaultWorkspaceName)).get(); // We are required to set the name here immediately wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str()); PNEWWORKSPACE->m_iID = WORKSPACEID; - PNEWWORKSPACE->m_szName = newDefaultWorkspaceName; } PNEWMONITOR->activeWorkspace = PNEWWORKSPACE->m_iID; @@ -174,6 +172,9 @@ 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 int damageBlinkCleanup = 0; // because double-buffered if (*PDEBUGOVERLAY == 1) { startRender = std::chrono::high_resolution_clock::now(); @@ -227,7 +228,7 @@ void Events::listener_monitorFrame(void* owner, void* data) { return; } - if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && PMONITOR->forceFullFrames == 0) { + 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 @@ -235,7 +236,7 @@ void Events::listener_monitorFrame(void* owner, void* data) { } // if we have no tracking or full tracking, invalidate the entire monitor - if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0) { + if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0 || damageBlinkCleanup > 0) { pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y); pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage); @@ -281,6 +282,16 @@ void Events::listener_monitorFrame(void* owner, void* data) { endRenderOverlay = std::chrono::high_resolution_clock::now(); } + if (*PDAMAGEBLINK && damageBlinkCleanup == 0) { + wlr_box monrect = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; + g_pHyprOpenGL->renderRect(&monrect, CColor(255,0,255,100), 0); + damageBlinkCleanup = 1; + } else if (*PDAMAGEBLINK) { + damageBlinkCleanup++; + if (damageBlinkCleanup > 3) + damageBlinkCleanup = 0; + } + wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); wlr_output_render_software_cursors(PMONITOR->output, NULL); @@ -299,6 +310,9 @@ void Events::listener_monitorFrame(void* owner, void* data) { if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR) pixman_region32_union_rect(&frameDamage, &frameDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y); + if (*PDAMAGEBLINK) + pixman_region32_union(&frameDamage, &frameDamage, &damage); + wlr_output_set_damage(PMONITOR->output, &frameDamage); pixman_region32_fini(&frameDamage); pixman_region32_fini(&damage); @@ -324,9 +338,9 @@ void Events::listener_monitorDestroy(void* owner, void* data) { SMonitor* pMonitor = nullptr; - for (auto& m : g_pCompositor->m_lMonitors) { - if (m.szName == OUTPUT->name) { - pMonitor = &m; + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->szName == OUTPUT->name) { + pMonitor = m.get(); break; } } @@ -335,7 +349,7 @@ void Events::listener_monitorDestroy(void* owner, void* data) { return; // Cleanup everything. Move windows back, snap cursor, shit. - const auto BACKUPMON = &g_pCompositor->m_lMonitors.front(); + const auto BACKUPMON = g_pCompositor->m_vMonitors.front().get(); if (!BACKUPMON) { Debug::log(CRIT, "No monitors! Unplugged last! Exiting."); @@ -351,9 +365,9 @@ void Events::listener_monitorDestroy(void* owner, void* data) { // move workspaces std::deque wspToMove; - for (auto& w : g_pCompositor->m_lWorkspaces) { - if (w.m_iMonitorID == pMonitor->ID) { - wspToMove.push_back(&w); + for (auto& w : g_pCompositor->m_vWorkspaces) { + if (w->m_iMonitorID == pMonitor->ID) { + wspToMove.push_back(w.get()); } } @@ -364,27 +378,23 @@ void Events::listener_monitorDestroy(void* owner, void* data) { pMonitor->activeWorkspace = -1; - for (auto it = g_pCompositor->m_lWorkspaces.begin(); it != g_pCompositor->m_lWorkspaces.end(); ++it) { - if (it->m_iMonitorID == pMonitor->ID) { - it = g_pCompositor->m_lWorkspaces.erase(it); - } - } + g_pCompositor->m_vWorkspaces.erase(std::remove_if(g_pCompositor->m_vWorkspaces.begin(), g_pCompositor->m_vWorkspaces.end(), [&](std::unique_ptr& el) { return el->m_iMonitorID == pMonitor->ID; })); Debug::log(LOG, "Removed monitor %s!", pMonitor->szName.c_str()); g_pEventManager->postEvent(SHyprIPCEvent("monitorremoved", pMonitor->szName)); - g_pCompositor->m_lMonitors.remove(*pMonitor); + 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; - for (auto& m : g_pCompositor->m_lMonitors) { - if (m.refreshRate > mostHz) { - pMonitorMostHz = &m; - mostHz = m.refreshRate; + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->refreshRate > mostHz) { + pMonitorMostHz = m.get(); + mostHz = m->refreshRate; } } diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp index 7e619632..cfb92f9b 100644 --- a/src/events/Popups.cpp +++ b/src/events/Popups.cpp @@ -76,8 +76,7 @@ void Events::listener_newPopup(void* owner, void* data) { const auto WLRPOPUP = (wlr_xdg_popup*)data; - g_pCompositor->m_lXDGPopups.push_back(SXDGPopup()); - const auto PNEWPOPUP = &g_pCompositor->m_lXDGPopups.back(); + const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique()).get(); const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID); @@ -97,8 +96,7 @@ void Events::listener_newPopupXDG(void* owner, void* data) { const auto WLRPOPUP = (wlr_xdg_popup*)data; - g_pCompositor->m_lXDGPopups.push_back(SXDGPopup()); - const auto PNEWPOPUP = &g_pCompositor->m_lXDGPopups.back(); + const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique()).get(); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); @@ -122,8 +120,7 @@ void Events::listener_newPopupFromPopupXDG(void* owner, void* data) { const auto WLRPOPUP = (wlr_xdg_popup*)data; - g_pCompositor->m_lXDGPopups.push_back(SXDGPopup()); - const auto PNEWPOPUP = &g_pCompositor->m_lXDGPopups.back(); + const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique()).get(); PNEWPOPUP->popup = WLRPOPUP; PNEWPOPUP->parentPopup = PPOPUP; @@ -170,5 +167,5 @@ void Events::listener_destroyPopupXDG(void* owner, void* data) { PPOPUP->pSurfaceTree = nullptr; } - g_pCompositor->m_lXDGPopups.remove(*PPOPUP); + g_pCompositor->m_vXDGPopups.erase(std::remove_if(g_pCompositor->m_vXDGPopups.begin(), g_pCompositor->m_vXDGPopups.end(), [&](std::unique_ptr& el) { return el.get() == PPOPUP; })); } \ No newline at end of file diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 76dfadda..3c1d83f5 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -43,6 +43,9 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW); PWINDOW->m_fAlpha = 255.f; + if (PWINDOW->m_iX11Type == 2) + g_pCompositor->moveUnmanagedX11ToWindows(PWINDOW); + // Set all windows tiled regardless of anything g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM); @@ -57,7 +60,7 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(PWINDOW); if (!PWINDOWSURFACE) { - g_pCompositor->m_lWindows.remove(*PWINDOW); + g_pCompositor->removeWindowFromVectorSafe(PWINDOW); return; } @@ -97,7 +100,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_iMonitorID = PMONITOR->ID; } else { const long int MONITOR = std::stoi(MONITORSTR); - if (MONITOR >= (long int)g_pCompositor->m_lMonitors.size() || MONITOR < (long int)0) + if (MONITOR >= (long int)g_pCompositor->m_vMonitors.size() || MONITOR < (long int)0) PWINDOW->m_iMonitorID = 0; else PWINDOW->m_iMonitorID = MONITOR; @@ -228,11 +231,9 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10,10); } - if (!PWINDOW->m_bNoFocus) + if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus) g_pCompositor->focusWindow(PWINDOW); - PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW, PWINDOW); - Debug::log(LOG, "Window got assigned a surfaceTreeNode %x", PWINDOW->m_pSurfaceTree); if (!PWINDOW->m_bIsX11) { @@ -260,16 +261,25 @@ void Events::listener_mapWindow(void* owner, void* data) { } if (requestsFullscreen) { + // fix fullscreen on requested (basically do a switcheroo) + if (PWORKSPACE->m_bHasFullscreenWindow) { + const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL, false); + g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen); + } + g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL); } + 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); } void Events::listener_unmapWindow(void* owner, void* data) { CWindow* PWINDOW = (CWindow*)owner; - Debug::log(LOG, "Window %x unmapped", PWINDOW); + Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str()); if (!PWINDOW->m_bIsX11) { Debug::log(LOG, "Unregistered late callbacks XDG: %x %x %x %x", &PWINDOW->hyprListener_commitWindow.m_sListener.link, &PWINDOW->hyprListener_setTitleWindow.m_sListener.link, &PWINDOW->hyprListener_fullscreenWindow.m_sListener.link, &PWINDOW->hyprListener_newPopupXDG.m_sListener.link); @@ -285,6 +295,11 @@ void Events::listener_unmapWindow(void* owner, void* data) { PWINDOW->hyprListener_setTitleWindow.removeCallback(); } + if (PWINDOW->m_bIsFullscreen) { + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, false); + g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen); + } + // Allow the renderer to catch the last frame. g_pHyprOpenGL->makeWindowSnapshot(PWINDOW); @@ -318,12 +333,14 @@ void Events::listener_unmapWindow(void* owner, void* data) { PWINDOW->m_bFadingOut = true; - g_pCompositor->m_lWindowsFadingOut.push_back(PWINDOW); + g_pCompositor->m_vWindowsFadingOut.emplace_back(PWINDOW); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)); + const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + // do the animation thing - PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec(); + PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition; PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec(); if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. @@ -347,7 +364,10 @@ void Events::listener_commitWindow(void* owner, void* data) { void Events::listener_destroyWindow(void* owner, void* data) { CWindow* PWINDOW = (CWindow*)owner; - Debug::log(LOG, "Window %x destroyed, queueing.", PWINDOW); + Debug::log(LOG, "Window %x destroyed, queueing. (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str()); + + if (PWINDOW->m_bIsX11) + Debug::log(LOG, "XWayland class raw: %s", PWINDOW->m_uSurface.xwayland->_class); if (PWINDOW == g_pCompositor->m_pLastWindow) { g_pCompositor->m_pLastWindow = nullptr; @@ -393,9 +413,9 @@ void Events::listener_fullscreenWindow(void* owner, void* data) { const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested; if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen) - g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, true); + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, REQUESTED->fullscreen); } else { - g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, true); + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, !PWINDOW->m_bIsFullscreen); } Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen); @@ -455,15 +475,18 @@ void Events::listener_configureX11(void* owner, void* data) { void Events::listener_surfaceXWayland(wl_listener* listener, void* data) { const auto XWSURFACE = (wlr_xwayland_surface*)data; - Debug::log(LOG, "New XWayland Surface created."); + Debug::log(LOG, "New XWayland Surface created (class %s).", XWSURFACE->_class); + if (XWSURFACE->parent) + Debug::log(LOG, "Window parent data: %s at %x", XWSURFACE->parent->_class, XWSURFACE->parent); - g_pCompositor->m_lWindows.emplace_back(); - const auto PNEWWINDOW = &g_pCompositor->m_lWindows.back(); + const auto PNEWWINDOW = XWSURFACE->override_redirect ? g_pCompositor->m_dUnmanagedX11Windows.emplace_back(std::make_unique()).get() : g_pCompositor->m_vWindows.emplace_back(std::make_unique()).get(); PNEWWINDOW->m_uSurface.xwayland = XWSURFACE; PNEWWINDOW->m_iX11Type = XWSURFACE->override_redirect ? 2 : 1; PNEWWINDOW->m_bIsX11 = true; + PNEWWINDOW->m_pX11Parent = g_pCompositor->getX11Parent(PNEWWINDOW); + PNEWWINDOW->hyprListener_mapWindow.initCallback(&XWSURFACE->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XWayland Window"); PNEWWINDOW->hyprListener_unmapWindow.initCallback(&XWSURFACE->events.unmap, &Events::listener_unmapWindow, PNEWWINDOW, "XWayland Window"); PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XWSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XWayland Window"); @@ -473,13 +496,12 @@ void Events::listener_newXDGSurface(wl_listener* listener, void* data) { // A window got opened const auto XDGSURFACE = (wlr_xdg_surface*)data; - Debug::log(LOG, "New XDG Surface created. (%ix%i at %i %i)", XDGSURFACE->current.geometry.width, XDGSURFACE->current.geometry.height, XDGSURFACE->current.geometry.x, XDGSURFACE->current.geometry.y); + Debug::log(LOG, "New XDG Surface created. (class: %s)", XDGSURFACE->toplevel->app_id); if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) return; // TODO: handle? - g_pCompositor->m_lWindows.emplace_back(); - const auto PNEWWINDOW = &g_pCompositor->m_lWindows.back(); + const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(std::make_unique()).get(); PNEWWINDOW->m_uSurface.xdg = XDGSURFACE; PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window"); diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index bb04869f..ceda2c57 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -33,56 +33,47 @@ public: // gets the current vector value (real time) const Vector2D& vec() const { - RASSERT(m_eVarType == AVARTYPE_VECTOR, "Tried to access vec() of AVARTYPE %i!", m_eVarType); return m_vValue; } // gets the current float value (real time) const float& fl() const { - RASSERT(m_eVarType == AVARTYPE_FLOAT, "Tried to access fl() of AVARTYPE %i!", m_eVarType); return m_fValue; } // gets the current color value (real time) const CColor& col() const { - RASSERT(m_eVarType == AVARTYPE_COLOR, "Tried to access col() of AVARTYPE %i!", m_eVarType); return m_cValue; } // gets the goal vector value const Vector2D& goalv() const { - RASSERT(m_eVarType == AVARTYPE_VECTOR, "Tried to access goalv() of AVARTYPE %i!", m_eVarType); return m_vGoal; } // gets the goal float value const float& goalf() const { - RASSERT(m_eVarType == AVARTYPE_FLOAT, "Tried to access goalf() of AVARTYPE %i!", m_eVarType); return m_fGoal; } // gets the goal color value const CColor& goalc() const { - RASSERT(m_eVarType == AVARTYPE_COLOR, "Tried to access goalc() of AVARTYPE %i!", m_eVarType); return m_cGoal; } void operator=(const Vector2D& v) { - RASSERT(m_eVarType == AVARTYPE_VECTOR, "Tried to access =v of AVARTYPE %i!", m_eVarType); m_vGoal = v; animationBegin = std::chrono::system_clock::now(); m_vBegun = m_vValue; } void operator=(const float& v) { - RASSERT(m_eVarType == AVARTYPE_FLOAT, "Tried to access =f of AVARTYPE %i!", m_eVarType); m_fGoal = v; animationBegin = std::chrono::system_clock::now(); m_fBegun = m_fValue; } void operator=(const CColor& v) { - RASSERT(m_eVarType == AVARTYPE_COLOR, "Tried to access =c of AVARTYPE %i!", m_eVarType); m_cGoal = v; animationBegin = std::chrono::system_clock::now(); m_cBegun = m_cValue; @@ -90,7 +81,6 @@ public: // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const Vector2D& v) { - RASSERT(m_eVarType == AVARTYPE_VECTOR, "Tried to access setValue(v) of AVARTYPE %i!", m_eVarType); m_vValue = v; animationBegin = std::chrono::system_clock::now(); m_vBegun = m_vValue; @@ -98,7 +88,6 @@ public: // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const float& v) { - RASSERT(m_eVarType == AVARTYPE_FLOAT, "Tried to access setValue(f) of AVARTYPE %i!", m_eVarType); m_fValue = v; animationBegin = std::chrono::system_clock::now(); m_vBegun = m_vValue; @@ -106,7 +95,6 @@ public: // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const CColor& v) { - RASSERT(m_eVarType == AVARTYPE_COLOR, "Tried to access setValue(c) of AVARTYPE %i!", m_eVarType); m_cValue = v; animationBegin = std::chrono::system_clock::now(); m_vBegun = m_vValue; @@ -114,21 +102,18 @@ public: // Sets the actual value and goal void setValueAndWarp(const Vector2D& v) { - RASSERT(m_eVarType == AVARTYPE_VECTOR, "Tried to access setValueAndWarp(v) of AVARTYPE %i!", m_eVarType); m_vGoal = v; warp(); } // Sets the actual value and goal void setValueAndWarp(const float& v) { - RASSERT(m_eVarType == AVARTYPE_FLOAT, "Tried to access setValueAndWarp(f) of AVARTYPE %i!", m_eVarType); m_fGoal = v; warp(); } // Sets the actual value and goal void setValueAndWarp(const CColor& v) { - RASSERT(m_eVarType == AVARTYPE_COLOR, "Tried to access setValueAndWarp(c) of AVARTYPE %i!", m_eVarType); m_cGoal = v; warp(); } diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index ce9dd788..cb1d88d6 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -4,6 +4,41 @@ #include "../Compositor.hpp" #include +static const float transforms[][9] = {{ + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + },{ + 0.0f, 1.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + },{ + -1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + },{ + 0.0f, -1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + },{ + -1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + },{ + 0.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + },{ + 1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + },{ + 0.0f, -1.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + }, +}; + void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) { ASSERT(pSignal); ASSERT(pListener); @@ -79,8 +114,8 @@ std::string getFormat(const char *fmt, ...) { } void scaleBox(wlr_box* box, float scale) { - box->width = std::round((box->x + box->width) * scale) - std::round(box->x * scale); - box->height = std::round((box->y + box->height) * scale) - std::round(box->y * scale); + box->width = std::round(box->width * scale); + box->height = std::round(box->height * scale); box->x = std::round(box->x * scale); box->y = std::round(box->y * scale); } @@ -135,8 +170,8 @@ float getPlusMinusKeywordResult(std::string source, float relative) { return result; } -bool isNumber(const std::string& str) { - return std::ranges::all_of(str.begin(), str.end(), [](char c) { return isdigit(c) != 0 || c == '-'; }); +bool isNumber(const std::string& str, bool allowfloat) { + return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); }); } bool isDirection(const std::string& arg) { @@ -184,12 +219,12 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { int lowestID = 99999; int highestID = -99999; - for (auto& w : g_pCompositor->m_lWorkspaces) { - if (w.m_iID < lowestID) - lowestID = w.m_iID; + for (auto& w : g_pCompositor->m_vWorkspaces) { + if (w->m_iID < lowestID) + lowestID = w->m_iID; - if (w.m_iID > highestID) - highestID = w.m_iID; + if (w->m_iID > highestID) + highestID = w->m_iID; } if (remains < 0) @@ -264,4 +299,25 @@ void logSystemInfo() { Debug::log(LOG, "os-release:"); Debug::log(NONE, "%s", execAndGet("cat /etc/os-release").c_str()); -} \ No newline at end of file +} + +void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) { + memset(mat, 0, sizeof(*mat) * 9); + + const float* t = transforms[tr]; + float x = 2.0f / w; + float y = 2.0f / h; + + // Rotation + reflection + mat[0] = x * t[0]; + mat[1] = x * t[1]; + mat[3] = y * -t[3]; + mat[4] = y * -t[4]; + + // Translation + mat[2] = -copysign(1.0f, mat[0] + mat[1]); + mat[5] = -copysign(1.0f, mat[3] + mat[4]); + + // Identity + mat[8] = 1.0f; +} diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 8470eb81..108ac7f7 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -7,11 +7,13 @@ void wlr_signal_emit_safe(struct wl_signal *signal, void *data); std::string getFormat(const char *fmt, ...); // Basically Debug::log to a string void scaleBox(wlr_box*, float); std::string removeBeginEndSpacesTabs(std::string); -bool isNumber(const std::string&); +bool isNumber(const std::string&, bool allowfloat = false); bool isDirection(const std::string&); int getWorkspaceIDFromString(const std::string&, std::string&); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); void logSystemInfo(); std::string execAndGet(const char*); -float getPlusMinusKeywordResult(std::string in, float relative); \ No newline at end of file +float getPlusMinusKeywordResult(std::string in, float relative); + +void matrixProjection(float mat[9], int w, int h, wl_output_transform tr); \ No newline at end of file diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp index 064ca181..c511b900 100644 --- a/src/helpers/SubsurfaceTree.cpp +++ b/src/helpers/SubsurfaceTree.cpp @@ -188,16 +188,27 @@ void Events::listener_commitSubsurface(void* owner, void* data) { // no damaging if it's not visible if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) { - if (g_pConfigManager->getInt("debug:log_damage")) + static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; + if (*PLOGDAMAGE) Debug::log(LOG, "Refusing to commit damage from %x because it's invisible.", pNode->pWindowOwner); return; } - int lx = 0, ly = 0; addSurfaceGlobalOffset(pNode, &lx, &ly); + // I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox) + // What this does is that basically, if the pNode is a child of some other node, on commit, + // it will also damage (check & damage if needed) all its siblings. + if (pNode->pParent) for (auto& cs : pNode->pParent->childSubsurfaces) { + const auto NODECOORDS = pNode->pSubsurface ? Vector2D(pNode->pSubsurface->pSubsurface->current.x, pNode->pSubsurface->pSubsurface->current.y) : Vector2D(); + + if (&cs != pNode->pSubsurface && cs.pSubsurface) { + g_pHyprRenderer->damageSurface(cs.pSubsurface->surface, lx - NODECOORDS.x + cs.pSubsurface->current.x, ly - NODECOORDS.y + cs.pSubsurface->current.y); + } + } + g_pHyprRenderer->damageSurface(pNode->pSurface, lx, ly); } diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index d6282224..33278053 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -71,7 +71,12 @@ struct SKeyboard { bool active = false; - xkb_rule_names currentRules; + std::string name = ""; + + xkb_rule_names currentRules = {0}; + int repeatRate = 0; + int repeatDelay = 0; + int numlockOn = -1; // For the list lookup bool operator==(const SKeyboard& rhs) { @@ -87,6 +92,8 @@ struct SMouse { pixman_region32_t confinedTo; + std::string name = ""; + DYNLISTENER(commitConstraint); DYNLISTENER(destroyMouse); @@ -168,6 +175,8 @@ struct STablet { wlr_tablet_v2_tablet* wlrTabletV2 = nullptr; wlr_input_device* wlrDevice = nullptr; + std::string name = ""; + bool operator==(const STablet& b) { return wlrDevice == b.wlrDevice; } @@ -186,6 +195,8 @@ struct STabletTool { bool active = true; + std::string name = ""; + DYNLISTENER(TabletToolDestroy); DYNLISTENER(TabletToolSetCursor); @@ -198,6 +209,8 @@ struct STabletPad { wlr_tablet_v2_tablet_pad* wlrTabletPadV2 = nullptr; STablet* pTabletParent = nullptr; + std::string name = ""; + DYNLISTENER(Attach); DYNLISTENER(Button); DYNLISTENER(Strip); diff --git a/src/helpers/Workspace.cpp b/src/helpers/Workspace.cpp index 90d234cb..7a6ad070 100644 --- a/src/helpers/Workspace.cpp +++ b/src/helpers/Workspace.cpp @@ -1,7 +1,7 @@ #include "Workspace.hpp" #include "../Compositor.hpp" -CWorkspace::CWorkspace(int monitorID, bool special) { +CWorkspace::CWorkspace(int monitorID, std::string name, bool special) { const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); if (!PMONITOR) { @@ -10,7 +10,7 @@ CWorkspace::CWorkspace(int monitorID, bool special) { } m_iMonitorID = monitorID; - + m_szName = name; m_bIsSpecialWorkspace = special; if (!special) { @@ -30,6 +30,8 @@ CWorkspace::CWorkspace(int monitorID, bool special) { m_fAlpha.m_pWorkspace = this; m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:workspaces_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces")->intValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces_curve")->strValue, nullptr, AVARDAMAGE_ENTIRE); m_fAlpha.setValueAndWarp(255.f); + + g_pEventManager->postEvent({"createworkspace", m_szName}, true); } CWorkspace::~CWorkspace() { @@ -42,6 +44,8 @@ CWorkspace::~CWorkspace() { wlr_ext_workspace_handle_v1_destroy(m_pWlrHandle); m_pWlrHandle = nullptr; } + + g_pEventManager->postEvent({"destroyworkspace", m_szName}, true); } void CWorkspace::startAnim(bool in, bool left, bool instant) { diff --git a/src/helpers/Workspace.hpp b/src/helpers/Workspace.hpp index 21b36e9f..2d0c5941 100644 --- a/src/helpers/Workspace.hpp +++ b/src/helpers/Workspace.hpp @@ -10,7 +10,7 @@ enum eFullscreenMode : uint8_t { class CWorkspace { public: - CWorkspace(int monitorID, bool special = false); + CWorkspace(int monitorID, std::string name, bool special = false); ~CWorkspace(); // Workspaces ID-based have IDs > 0 diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 135f9635..7255aae9 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -12,7 +12,7 @@ void CHyprError::createQueued() { m_tTexture.destroyTexture(); } - const auto PMONITOR = &g_pCompositor->m_lMonitors.front(); + 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); @@ -95,11 +95,11 @@ void CHyprError::draw() { m_tTexture.destroyTexture(); m_bIsCreated = false; m_szQueued = ""; - g_pHyprRenderer->damageMonitor(&g_pCompositor->m_lMonitors.front()); + g_pHyprRenderer->damageMonitor(g_pCompositor->m_vMonitors.front().get()); return; } - const auto PMONITOR = &g_pCompositor->m_lMonitors.front(); + const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); if (g_pHyprOpenGL->m_RenderData.pMonitor != PMONITOR) return; // wrong mon diff --git a/src/includes.hpp b/src/includes.hpp index 3aca4331..2455171d 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -88,6 +88,9 @@ extern "C" { #include #include #include +#include +#include +#include } #undef class @@ -114,3 +117,5 @@ extern "C" { #include "helpers/Vector2D.hpp" #include "ext-workspace-unstable-v1-protocol.h" + +#include \ No newline at end of file diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index c72dbb99..33af48a3 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -176,9 +176,11 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) { g_pXWaylandManager->setWindowSize(PWINDOW, calcSize); } + + PWINDOW->updateWindowDecos(); } -void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) { +void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) { if (pWindow->m_bIsFloating) return; @@ -309,7 +311,7 @@ void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) { } } -void CHyprDwindleLayout::onWindowRemoved(CWindow* pWindow) { +void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) { const auto PNODE = getNodeFromWindow(pWindow); @@ -399,145 +401,8 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) { } } -void CHyprDwindleLayout::changeWindowFloatingMode(CWindow* pWindow) { - - if (pWindow->m_bIsFullscreen) { - Debug::log(LOG, "Rejecting a change float order because window is fullscreen."); - - // restore its' floating mode - pWindow->m_bIsFloating = !pWindow->m_bIsFloating; - return; - } - - const auto PNODE = getNodeFromWindow(pWindow); - - if (!PNODE) { - const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f); - pWindow->m_iMonitorID = PNEWMON->ID; - pWindow->m_iWorkspaceID = PNEWMON->activeWorkspace; - - // save real pos cuz the func applies the default 5,5 mid - const auto PSAVEDPOS = pWindow->m_vRealPosition.vec(); - const auto PSAVEDSIZE = pWindow->m_vRealSize.vec(); - - // if the window is pseudo, update its size - pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec(); - - onWindowCreated(pWindow); - - pWindow->m_vRealPosition.setValue(PSAVEDPOS); - pWindow->m_vRealSize.setValue(PSAVEDSIZE); - - // fix pseudo leaving artifacts - g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); - } else { - onWindowRemoved(pWindow); - - g_pCompositor->moveWindowToTop(pWindow); - } -} - -void CHyprDwindleLayout::onBeginDragWindow() { - - const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; - - m_vBeginDragSizeXY = Vector2D(); - - // Window will be floating. Let's check if it's valid. It should be, but I don't like crashing. - if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) { - Debug::log(ERR, "Dragging attempted on an invalid window!"); - return; - } - - if (DRAGGINGWINDOW->m_bIsFullscreen) { - Debug::log(LOG, "Rejecting drag on a fullscreen window."); - return; - } - - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(DRAGGINGWINDOW->m_iWorkspaceID); - - if (PWORKSPACE->m_bHasFullscreenWindow) { - Debug::log(LOG, "Rejecting drag on a fullscreen workspace."); - return; - } - - DRAGGINGWINDOW->m_bDraggingTiled = false; - - if (!DRAGGINGWINDOW->m_bIsFloating) { - if (g_pInputManager->dragButton == BTN_LEFT) { - changeWindowFloatingMode(DRAGGINGWINDOW); - DRAGGINGWINDOW->m_bIsFloating = true; - DRAGGINGWINDOW->m_bDraggingTiled = true; - } - } - - m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal(); - m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.vec(); - m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.vec(); - m_vLastDragXY = m_vBeginDragXY; - - g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); -} - -void CHyprDwindleLayout::onEndDragWindow() { - const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; - - if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) - return; - - if (DRAGGINGWINDOW->m_bDraggingTiled) { - DRAGGINGWINDOW->m_bIsFloating = false; - changeWindowFloatingMode(DRAGGINGWINDOW); - } - - g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); -} - -void CHyprDwindleLayout::onMouseMove(const Vector2D& mousePos) { - const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; - - // Window invalid or drag begin size 0,0 meaning we rejected it. - if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) { - g_pInputManager->currentlyDraggedWindow = nullptr; - return; - } - - const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); - const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y); - - if (abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) - return; - - m_vLastDragXY = mousePos; - - g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); - - if (g_pInputManager->dragButton == BTN_LEFT) { - DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA); - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); - } else { - if (DRAGGINGWINDOW->m_bIsFloating) { - DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(m_vBeginDragSizeXY + DELTA); - DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(Vector2D(std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().x, (double)20, (double)999999), std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().y, (double)20, (double)999999))); - - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); - } else { - resizeActiveWindow(TICKDELTA, DRAGGINGWINDOW); - } - } - - // get middle point - Vector2D middle = DRAGGINGWINDOW->m_vRealPosition.vec() + DRAGGINGWINDOW->m_vRealSize.vec() / 2.f; - - // and check its monitor - const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle); - - if (PMONITOR) { - DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID; - DRAGGINGWINDOW->m_iWorkspaceID = PMONITOR->activeWorkspace; - } - - g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); +bool CHyprDwindleLayout::isWindowTiled(CWindow* pWindow) { + return getNodeFromWindow(pWindow) != nullptr; } void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* pWindow) { @@ -551,6 +416,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* if (!PNODE) { PWINDOW->m_vRealSize = Vector2D(std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).x, (double)20, (double)999999), std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).y, (double)20, (double)999999)); + PWINDOW->updateWindowDecos(); return; } @@ -627,55 +493,6 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* TOPCONTAINER->recalcSizePosRecursive(); } -void CHyprDwindleLayout::onWindowCreatedFloating(CWindow* pWindow) { - wlr_box desiredGeometry = {0}; - g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - - if (!PMONITOR){ - Debug::log(ERR, "Window %x (%s) has an invalid monitor in onWindowCreatedFloating!!!", pWindow, pWindow->m_szTitle.c_str()); - return; - } - - if (desiredGeometry.width <= 0 || desiredGeometry.height <= 0) { - const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow); - pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height); - pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.vec().x) / 2.f, PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.vec().y) / 2.f); - - } else { - // we respect the size. - pWindow->m_vRealSize = Vector2D(desiredGeometry.width, desiredGeometry.height); - - // check if it's on the correct monitor! - 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 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 { - // if it is, we respect where it wants to put itself, but apply monitor offset if outside - // most of these are popups - - if (const auto POPENMON = g_pCompositor->getMonitorFromVector(middlePoint); POPENMON->ID != PMONITOR->ID) { - pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y) - POPENMON->vecPosition + PMONITOR->vecPosition; - } else { - pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y); - } - } - } - - if (pWindow->m_bX11DoesntWantBorders) { - pWindow->m_vRealPosition.setValue(pWindow->m_vRealPosition.goalv()); - pWindow->m_vRealSize.setValue(pWindow->m_vRealSize.goalv()); - } - - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); - g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace); - - g_pCompositor->moveWindowToTop(pWindow); -} - void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) { if (!g_pCompositor->windowValidMapped(pWindow)) return; @@ -731,6 +548,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight; fakeNode.workspaceID = pWindow->m_iWorkspaceID; + pWindow->m_vPosition = fakeNode.position; + pWindow->m_vSize = fakeNode.size; applyNodeDataToWindow(&fakeNode); } @@ -1001,20 +820,4 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) { std::string CHyprDwindleLayout::getLayoutName() { return "dwindle"; -} - -void CHyprDwindleLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) { - const auto PWINDOW = pWindow ? pWindow : g_pCompositor->m_pLastWindow; - - if (!g_pCompositor->windowValidMapped(PWINDOW)) - return; - - if (!PWINDOW->m_bIsFloating) { - Debug::log(LOG, "Dwindle cannot move a tiled window in moveActiveWindow!"); - return; - } - - PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + delta; - - g_pHyprRenderer->damageWindow(PWINDOW); } \ No newline at end of file diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 3f32ff0b..bd73a315 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -42,17 +42,12 @@ struct SDwindleNodeData { class CHyprDwindleLayout : public IHyprLayout { public: - virtual void onWindowCreated(CWindow*); - virtual void onWindowRemoved(CWindow*); + virtual void onWindowCreatedTiling(CWindow*); + virtual void onWindowRemovedTiling(CWindow*); + virtual bool isWindowTiled(CWindow*); virtual void recalculateMonitor(const int&); virtual void recalculateWindow(CWindow*); - virtual void changeWindowFloatingMode(CWindow*); - virtual void onBeginDragWindow(); virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr); - virtual void moveActiveWindow(const Vector2D&, CWindow* pWindow = nullptr); - virtual void onEndDragWindow(); - virtual void onMouseMove(const Vector2D&); - virtual void onWindowCreatedFloating(CWindow*); virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool); virtual std::any layoutMessage(SLayoutMessageHeader, std::string); virtual SWindowRenderLayoutHints requestRenderHints(CWindow*); @@ -60,15 +55,10 @@ public: virtual void alterSplitRatioBy(CWindow*, float); virtual std::string getLayoutName(); - private: +private: std::list m_lDwindleNodesData; - Vector2D m_vBeginDragXY; - Vector2D m_vLastDragXY; - Vector2D m_vBeginDragPositionXY; - Vector2D m_vBeginDragSizeXY; - int getNodesOnWorkspace(const int&); void applyNodeDataToWindow(SDwindleNodeData*); SDwindleNodeData* getNodeFromWindow(CWindow*); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp new file mode 100644 index 00000000..a7f2facf --- /dev/null +++ b/src/layout/IHyprLayout.cpp @@ -0,0 +1,233 @@ +#include "IHyprLayout.hpp" +#include "../defines.hpp" +#include "../Compositor.hpp" + +void IHyprLayout::onWindowCreated(CWindow* pWindow) { + if (pWindow->m_bIsFloating) { + onWindowCreatedFloating(pWindow); + } else { + onWindowCreatedTiling(pWindow); + } +} + +void IHyprLayout::onWindowRemoved(CWindow* pWindow) { + if (pWindow->m_bIsFloating) { + onWindowRemovedFloating(pWindow); + } else { + onWindowRemovedTiling(pWindow); + } +} + +void IHyprLayout::onWindowRemovedFloating(CWindow* pWindow) { + return; // no-op +} + +void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) { + wlr_box desiredGeometry = {0}; + g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + + if (!PMONITOR) { + Debug::log(ERR, "Window %x (%s) has an invalid monitor in onWindowCreatedFloating!!!", pWindow, pWindow->m_szTitle.c_str()); + return; + } + + if (desiredGeometry.width <= 0 || desiredGeometry.height <= 0) { + const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow); + pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height); + pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.vec().x) / 2.f, PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.vec().y) / 2.f); + + } else { + // we respect the size. + pWindow->m_vRealSize = Vector2D(desiredGeometry.width, desiredGeometry.height); + + // check if it's on the correct monitor! + 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 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 { + // if it is, we respect where it wants to put itself, but apply monitor offset if outside + // most of these are popups + + if (const auto POPENMON = g_pCompositor->getMonitorFromVector(middlePoint); POPENMON->ID != PMONITOR->ID) { + pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y) - POPENMON->vecPosition + PMONITOR->vecPosition; + } else { + pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y); + } + } + } + + if (pWindow->m_bX11DoesntWantBorders) { + pWindow->m_vRealPosition.setValue(pWindow->m_vRealPosition.goalv()); + pWindow->m_vRealSize.setValue(pWindow->m_vRealSize.goalv()); + } + + g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); + g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace); + + g_pCompositor->moveWindowToTop(pWindow); +} + +void IHyprLayout::onBeginDragWindow() { + const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; + + m_vBeginDragSizeXY = Vector2D(); + + // Window will be floating. Let's check if it's valid. It should be, but I don't like crashing. + if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) { + Debug::log(ERR, "Dragging attempted on an invalid window!"); + return; + } + + if (DRAGGINGWINDOW->m_bIsFullscreen) { + Debug::log(LOG, "Rejecting drag on a fullscreen window."); + return; + } + + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(DRAGGINGWINDOW->m_iWorkspaceID); + + if (PWORKSPACE->m_bHasFullscreenWindow) { + Debug::log(LOG, "Rejecting drag on a fullscreen workspace."); + return; + } + + DRAGGINGWINDOW->m_bDraggingTiled = false; + + if (!DRAGGINGWINDOW->m_bIsFloating) { + if (g_pInputManager->dragButton == BTN_LEFT) { + changeWindowFloatingMode(DRAGGINGWINDOW); + DRAGGINGWINDOW->m_bIsFloating = true; + DRAGGINGWINDOW->m_bDraggingTiled = true; + } + } + + m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal(); + m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.vec(); + m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.vec(); + m_vLastDragXY = m_vBeginDragXY; + + g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); +} + +void IHyprLayout::onEndDragWindow() { + const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; + + if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) + return; + + if (DRAGGINGWINDOW->m_bDraggingTiled) { + DRAGGINGWINDOW->m_bIsFloating = false; + changeWindowFloatingMode(DRAGGINGWINDOW); + } + + g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); +} + +void IHyprLayout::onMouseMove(const Vector2D& mousePos) { + const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; + + // Window invalid or drag begin size 0,0 meaning we rejected it. + if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) { + g_pInputManager->currentlyDraggedWindow = nullptr; + return; + } + + const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); + const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y); + + if (abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) + return; + + m_vLastDragXY = mousePos; + + g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); + + if (g_pInputManager->dragButton == BTN_LEFT) { + DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA); + + DRAGGINGWINDOW->updateWindowDecos(); + + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); + } else { + if (DRAGGINGWINDOW->m_bIsFloating) { + DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(m_vBeginDragSizeXY + DELTA); + DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(Vector2D(std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().x, (double)20, (double)999999), std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().y, (double)20, (double)999999))); + + DRAGGINGWINDOW->updateWindowDecos(); + + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); + } else { + resizeActiveWindow(TICKDELTA, DRAGGINGWINDOW); + } + } + + // get middle point + Vector2D middle = DRAGGINGWINDOW->m_vRealPosition.vec() + DRAGGINGWINDOW->m_vRealSize.vec() / 2.f; + + // and check its monitor + const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle); + + if (PMONITOR) { + DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID; + DRAGGINGWINDOW->m_iWorkspaceID = PMONITOR->activeWorkspace; + } + + g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); +} + +void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) { + + if (pWindow->m_bIsFullscreen) { + Debug::log(LOG, "Rejecting a change float order because window is fullscreen."); + + // restore its' floating mode + pWindow->m_bIsFloating = !pWindow->m_bIsFloating; + return; + } + + const auto TILED = isWindowTiled(pWindow); + + if (!TILED) { + const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f); + pWindow->m_iMonitorID = PNEWMON->ID; + pWindow->m_iWorkspaceID = PNEWMON->activeWorkspace; + + // save real pos cuz the func applies the default 5,5 mid + const auto PSAVEDPOS = pWindow->m_vRealPosition.vec(); + const auto PSAVEDSIZE = pWindow->m_vRealSize.vec(); + + // if the window is pseudo, update its size + pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec(); + + onWindowCreatedTiling(pWindow); + + pWindow->m_vRealPosition.setValue(PSAVEDPOS); + pWindow->m_vRealSize.setValue(PSAVEDSIZE); + + // fix pseudo leaving artifacts + g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); + } else { + onWindowRemovedTiling(pWindow); + + g_pCompositor->moveWindowToTop(pWindow); + } +} + +void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) { + const auto PWINDOW = pWindow ? pWindow : g_pCompositor->m_pLastWindow; + + if (!g_pCompositor->windowValidMapped(PWINDOW)) + return; + + if (!PWINDOW->m_bIsFloating) { + Debug::log(LOG, "Dwindle cannot move a tiled window in moveActiveWindow!"); + return; + } + + PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + delta; + + g_pHyprRenderer->damageWindow(PWINDOW); +} \ No newline at end of file diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index d7102761..d214bf73 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -22,11 +22,21 @@ public: The layout HAS TO set the goal pos and size (anim mgr will use it) If !animationinprogress, then the anim mgr will not apply an anim. */ - virtual void onWindowCreated(CWindow*) = 0; + virtual void onWindowCreated(CWindow*); + virtual void onWindowCreatedTiling(CWindow*) = 0; + virtual void onWindowCreatedFloating(CWindow*); + + /* + Return tiled status + */ + virtual bool isWindowTiled(CWindow*) = 0; + /* Called when a window is removed (unmapped) */ - virtual void onWindowRemoved(CWindow*) = 0; + virtual void onWindowRemoved(CWindow*); + virtual void onWindowRemovedTiling(CWindow*) = 0; + virtual void onWindowRemovedFloating(CWindow*); /* Called when the monitor requires a layout recalculation this usually means reserved area changes @@ -42,13 +52,13 @@ public: /* Called when a window is requested to be floated */ - virtual void changeWindowFloatingMode(CWindow*) = 0; + virtual void changeWindowFloatingMode(CWindow*); /* Called when a window is clicked on, beginning a drag this might be a resize, move, whatever the layout defines it as. */ - virtual void onBeginDragWindow() = 0; + virtual void onBeginDragWindow(); /* Called when a user requests a resize of the current window by a vec Vector2D holds pixel values @@ -60,24 +70,18 @@ public: Vector2D holds pixel values Optional pWindow for a specific window */ - virtual void moveActiveWindow(const Vector2D&, CWindow* pWindow = nullptr) = 0; + virtual void moveActiveWindow(const Vector2D&, CWindow* pWindow = nullptr); /* Called when a window is ended being dragged (mouse up) */ - virtual void onEndDragWindow() = 0; + virtual void onEndDragWindow(); /* Called whenever the mouse moves, should the layout want to do anything with it. Useful for dragging. */ - virtual void onMouseMove(const Vector2D&) = 0; - /* - Called when a window is created, but is requesting to be floated. - Warning: this also includes stuff like popups, incorrect handling - of which can result in a crash! - */ - virtual void onWindowCreatedFloating(CWindow*) = 0; + virtual void onMouseMove(const Vector2D&); /* Called when a window / the user requests to toggle the fullscreen state of a window @@ -116,4 +120,10 @@ public: Called when something wants the current layout's name */ virtual std::string getLayoutName() = 0; + +private: + Vector2D m_vBeginDragXY; + Vector2D m_vLastDragXY; + Vector2D m_vBeginDragPositionXY; + Vector2D m_vBeginDragSizeXY; }; \ No newline at end of file diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 2ceefdd4..e48b4d1e 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -37,9 +37,18 @@ void CAnimationManager::tick() { DEFAULTBEZIER = m_mBezierCurves.find("default"); for (auto& av : m_lAnimatedVariables) { + + // first of all, check if we need to update it at all + if (!av->isBeingAnimated()) + continue; + // get speed const auto SPEED = *av->m_pSpeed == 0 ? *PANIMSPEED : *av->m_pSpeed; + // get the spent % (0 - 1) + const auto DURATIONPASSED = std::chrono::duration_cast(std::chrono::system_clock::now() - av->animationBegin).count(); + const float SPENT = std::clamp((DURATIONPASSED / 100.f) / SPEED, 0.f, 1.f); + // window stuff const auto PWINDOW = (CWindow*)av->m_pWindow; const auto PWORKSPACE = (CWorkspace*)av->m_pWorkspace; @@ -47,7 +56,7 @@ void CAnimationManager::tick() { wlr_box WLRBOXPREV = {0,0,0,0}; if (PWINDOW) { - WLRBOXPREV = {(int)PWINDOW->m_vRealPosition.vec().x - (int)*PBORDERSIZE - 1, (int)PWINDOW->m_vRealPosition.vec().y - (int)*PBORDERSIZE - 1, (int)PWINDOW->m_vRealSize.vec().x + 2 * (int)*PBORDERSIZE + 2, (int)PWINDOW->m_vRealSize.vec().y + 2 * (int)*PBORDERSIZE + 2}; + WLRBOXPREV = PWINDOW->getFullWindowBoundingBox(); } else if (PWORKSPACE) { const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y}; @@ -58,84 +67,68 @@ void CAnimationManager::tick() { // beziers are with a switch unforto // TODO: maybe do something cleaner - // get the spent % (0 - 1) - const auto DURATIONPASSED = std::chrono::duration_cast(std::chrono::system_clock::now() - av->animationBegin).count(); - const float SPENT = std::clamp((DURATIONPASSED / 100.f) / SPEED, 0.f, 1.f); - switch (av->m_eVarType) { case AVARTYPE_FLOAT: { - if (!deltazero(av->m_fValue, av->m_fGoal)) { - - // for disabled anims just warp - if (av->m_pEnabled == 0 || animationsDisabled) { - av->warp(); - break; - } - - const auto DELTA = av->m_fGoal - av->m_fBegun; - const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); - - if (BEZIER != m_mBezierCurves.end()) - av->m_fValue = av->m_fBegun + BEZIER->second.getYForPoint(SPENT) * DELTA; - else - av->m_fValue = av->m_fBegun + DEFAULTBEZIER->second.getYForPoint(SPENT) * DELTA; - - if (SPENT >= 1.f) { - av->warp(); - } - } else { - continue; // dont process + // for disabled anims just warp + if (*av->m_pEnabled == 0 || animationsDisabled) { + av->warp(); + break; } + + if (SPENT >= 1.f) { + av->warp(); + break; + } + + const auto DELTA = av->m_fGoal - av->m_fBegun; + const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); + + if (BEZIER != m_mBezierCurves.end()) + av->m_fValue = av->m_fBegun + BEZIER->second.getYForPoint(SPENT) * DELTA; + else + av->m_fValue = av->m_fBegun + DEFAULTBEZIER->second.getYForPoint(SPENT) * DELTA; break; } case AVARTYPE_VECTOR: { - if (!deltazero(av->m_vValue, av->m_vGoal)) { - - // for disabled anims just warp - if (av->m_pEnabled == 0 || animationsDisabled) { - av->warp(); - break; - } - - const auto DELTA = av->m_vGoal - av->m_vBegun; - const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); - - if (BEZIER != m_mBezierCurves.end()) - av->m_vValue = av->m_vBegun + DELTA * BEZIER->second.getYForPoint(SPENT); - else - av->m_vValue = av->m_vBegun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT); - - if (SPENT >= 1.f) { - av->warp(); - } - } else { - continue; // dont process + // for disabled anims just warp + if (*av->m_pEnabled == 0 || animationsDisabled) { + av->warp(); + break; } + + if (SPENT >= 1.f) { + av->warp(); + break; + } + + const auto DELTA = av->m_vGoal - av->m_vBegun; + const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); + + if (BEZIER != m_mBezierCurves.end()) + av->m_vValue = av->m_vBegun + DELTA * BEZIER->second.getYForPoint(SPENT); + else + av->m_vValue = av->m_vBegun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT); break; } case AVARTYPE_COLOR: { - if (!deltazero(av->m_cValue, av->m_cGoal)) { - - // for disabled anims just warp - if (av->m_pEnabled == 0 || animationsDisabled) { - av->warp(); - break; - } - - const auto DELTA = av->m_cGoal - av->m_cBegun; - const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); - - if (BEZIER != m_mBezierCurves.end()) - av->m_cValue = av->m_cBegun + DELTA * BEZIER->second.getYForPoint(SPENT); - else - av->m_cValue = av->m_cBegun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT); - - if (SPENT >= 1.f) { - av->warp(); - } - } else { - continue; // dont process + // for disabled anims just warp + if (*av->m_pEnabled == 0 || animationsDisabled) { + av->warp(); + break; } + + if (SPENT >= 1.f) { + av->warp(); + break; + } + + const auto DELTA = av->m_cGoal - av->m_cBegun; + const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); + + if (BEZIER != m_mBezierCurves.end()) + av->m_cValue = av->m_cBegun + DELTA * BEZIER->second.getYForPoint(SPENT); + else + av->m_cValue = av->m_cBegun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT); break; } default: { @@ -150,8 +143,16 @@ void CAnimationManager::tick() { if (PWINDOW) { g_pHyprRenderer->damageWindow(PWINDOW); - for (auto& wd : PWINDOW->m_dWindowDecorations) { - wd->updateWindow(PWINDOW); + PWINDOW->updateWindowDecos(); + } else if (PWORKSPACE) { + for (auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_bHidden) + continue; + + if (w->m_iWorkspaceID != PWORKSPACE->m_iID) + continue; + + w->updateWindowDecos(); } } break; diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index e42e87c2..22299a01 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -87,7 +87,7 @@ void CEventManager::startThread() { // write all queued events for (auto& ev : m_dQueuedEvents) { - std::string eventString = ev.event + ">>" + ev.data + "\n"; + std::string eventString = (ev.event + ">>" + ev.data).substr(0, 1022) + "\n"; for (auto& fd : m_dAcceptedSocketFDs) { write(fd, eventString.c_str(), eventString.length()); } @@ -104,9 +104,9 @@ void CEventManager::startThread() { }).detach(); } -void CEventManager::postEvent(const SHyprIPCEvent event) { +void CEventManager::postEvent(const SHyprIPCEvent event, bool force) { - if (m_bIgnoreEvents) { + if (m_bIgnoreEvents && !force) { Debug::log(WARN, "Suppressed (ignoreevents true) event of type %s, content: %s",event.event.c_str(), event.data.c_str()); return; } diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index ae630ce8..b9598bca 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -15,7 +15,7 @@ class CEventManager { public: CEventManager(); - void postEvent(const SHyprIPCEvent event); + void postEvent(const SHyprIPCEvent event, bool force = false); void startThread(); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 10694e1b..cb091c9f 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -30,7 +30,8 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["resizeactive"] = resizeActive; m_mDispatchers["moveactive"] = moveActive; m_mDispatchers["cyclenext"] = circleNext; - m_mDispatchers["focuswindowbyclass"] = focusWindowByClass; + m_mDispatchers["focuswindowbyclass"] = focusWindow; + m_mDispatchers["focuswindow"] = focusWindow; m_mDispatchers["submap"] = setSubmap; } @@ -108,7 +109,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t return found; } -bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { +bool CKeybindManager::handleVT(xkb_keysym_t keysym) { // Handles the CTRL+ALT+FX TTY keybinds if (!(keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12)) return false; @@ -118,20 +119,37 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { const int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; wlr_session_change_vt(PSESSION, TTY); - for (auto& m : g_pCompositor->m_lMonitors) { - g_pHyprOpenGL->destroyMonitorResources(&m); // mark resources as unusable anymore - m.noFrameSchedule = true; - m.framesToSkip = 2; + for (auto& m : g_pCompositor->m_vMonitors) { + g_pHyprOpenGL->destroyMonitorResources(m.get()); // mark resources as unusable anymore + m->noFrameSchedule = true; + m->framesToSkip = 2; } Debug::log(LOG, "Switched to VT %i, destroyed all render data, frames to skip for each: 2", TTY); - + return true; } return false; } +bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { + if (handleVT(keysym)) + return true; + + // handle ESC while in kill mode + if (g_pInputManager->getClickMode() == CLICKMODE_KILL) { + const auto KBKEY = xkb_keysym_from_name("ESCAPE", XKB_KEYSYM_CASE_INSENSITIVE); + + if (keysym == KBKEY) { + g_pInputManager->setClickMode(CLICKMODE_DEFAULT); + return true; + } + } + + return false; +} + // Dispatchers void CKeybindManager::spawn(std::string args) { @@ -204,6 +222,9 @@ void CKeybindManager::toggleActiveFloating(std::string args) { const auto ACTIVEWINDOW = g_pCompositor->m_pLastWindow; if (g_pCompositor->windowValidMapped(ACTIVEWINDOW)) { + // remove drag status + g_pInputManager->currentlyDraggedWindow = nullptr; + ACTIVEWINDOW->m_bIsFloating = !ACTIVEWINDOW->m_bIsFloating; if (ACTIVEWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) { @@ -319,8 +340,7 @@ void CKeybindManager::changeworkspace(std::string args) { if (const auto POLDWORKSPACE = g_pCompositor->getWorkspaceByID(OLDWORKSPACE); POLDWORKSPACE) POLDWORKSPACE->startAnim(false, ANIMTOLEFT); - g_pCompositor->m_lWorkspaces.emplace_back(PMONITOR->ID, workspaceToChangeTo == SPECIAL_WORKSPACE_ID); - const auto PWORKSPACE = &g_pCompositor->m_lWorkspaces.back(); + const auto PWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique(PMONITOR->ID, workspaceName, workspaceToChangeTo == SPECIAL_WORKSPACE_ID)).get(); // start anim on new workspace PWORKSPACE->startAnim(true, ANIMTOLEFT); @@ -331,7 +351,6 @@ void CKeybindManager::changeworkspace(std::string args) { PWORKSPACE->m_iID = workspaceToChangeTo; PWORKSPACE->m_iMonitorID = PMONITOR->ID; - PWORKSPACE->m_szName = workspaceName; PMONITOR->specialWorkspaceOpen = false; @@ -437,8 +456,8 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { toggleSpecialWorkspace(""); g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false, true); - for (auto& m : g_pCompositor->m_lMonitors) - m.specialWorkspaceOpen = false; + for (auto& m : g_pCompositor->m_vMonitors) + m->specialWorkspaceOpen = false; } g_pInputManager->refocus(); @@ -643,7 +662,7 @@ void CKeybindManager::focusMonitor(std::string arg) { Debug::log(ERR, "Error in focusMonitor: invalid num"); } - if (monID > -1 && monID < (int)g_pCompositor->m_lMonitors.size()) { + if (monID > -1 && monID < (int)g_pCompositor->m_vMonitors.size()) { changeworkspace(std::to_string(g_pCompositor->getMonitorFromID(monID)->activeWorkspace)); } else { Debug::log(ERR, "Error in focusMonitor: invalid arg 1"); @@ -662,9 +681,9 @@ void CKeybindManager::focusMonitor(std::string arg) { return; } } else { - for (auto& m : g_pCompositor->m_lMonitors) { - if (m.szName == arg) { - changeworkspace(std::to_string(m.activeWorkspace)); + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->szName == arg) { + changeworkspace(std::to_string(m->activeWorkspace)); return; } } @@ -724,11 +743,11 @@ void CKeybindManager::workspaceOpt(std::string args) { PWORKSPACE->m_bDefaultPseudo = !PWORKSPACE->m_bDefaultPseudo; // apply - for (auto& w : g_pCompositor->m_lWindows) { - if (!w.m_bIsMapped || w.m_iWorkspaceID != PWORKSPACE->m_iID) + for (auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_iWorkspaceID != PWORKSPACE->m_iID) continue; - w.m_bIsPseudotiled = PWORKSPACE->m_bDefaultPseudo; + w->m_bIsPseudotiled = PWORKSPACE->m_bDefaultPseudo; } } else if (args == "allfloat") { PWORKSPACE->m_bDefaultFloating = !PWORKSPACE->m_bDefaultFloating; @@ -736,8 +755,8 @@ void CKeybindManager::workspaceOpt(std::string args) { // we make a copy because changeWindowFloatingMode might invalidate the iterator std::deque ptrs; - for (auto& w : g_pCompositor->m_lWindows) - ptrs.push_back(&w); + for (auto& w : g_pCompositor->m_vWindows) + ptrs.push_back(w.get()); for (auto& w : ptrs) { if (!w->m_bIsMapped || w->m_iWorkspaceID != PWORKSPACE->m_iID) @@ -841,8 +860,8 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) { bool open = false; - for (auto& m : g_pCompositor->m_lMonitors) { - if (m.specialWorkspaceOpen) { + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->specialWorkspaceOpen) { open = true; break; } @@ -854,10 +873,10 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) { Debug::log(LOG, "Toggling special workspace to open"); if (open) { - for (auto& m : g_pCompositor->m_lMonitors) { - if (m.specialWorkspaceOpen != !open) { - m.specialWorkspaceOpen = !open; - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m.ID); + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->specialWorkspaceOpen != !open) { + m->specialWorkspaceOpen = !open; + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false); } @@ -866,17 +885,28 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) { g_pCompositor->m_pLastMonitor->specialWorkspaceOpen = true; g_pLayoutManager->getCurrentLayout()->recalculateMonitor(g_pCompositor->m_pLastMonitor->ID); - g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(true, true); + const auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID); + + PSPECIALWORKSPACE->startAnim(true, true); + PSPECIALWORKSPACE->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID; } g_pInputManager->refocus(); } void CKeybindManager::forceRendererReload(std::string args) { - for (auto& m : g_pCompositor->m_lMonitors) { - auto rule = g_pConfigManager->getMonitorRuleFor(m.szName); - g_pHyprRenderer->applyMonitorRule(&m, &rule, true); + bool overAgain = false; + + for (auto& m : g_pCompositor->m_vMonitors) { + auto rule = g_pConfigManager->getMonitorRuleFor(m->szName); + if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { + overAgain = true; + break; + } } + + if (overAgain) + forceRendererReload(args); } void CKeybindManager::resizeActive(std::string args) { @@ -988,25 +1018,36 @@ void CKeybindManager::circleNext(std::string) { wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, MIDPOINT.x, MIDPOINT.y); } -void CKeybindManager::focusWindowByClass(std::string clazz) { - std::regex classCheck(clazz); +void CKeybindManager::focusWindow(std::string regexp) { + bool titleRegex = false; + std::regex regexCheck(regexp); + if (regexp.find("title:") == 0) { + titleRegex = true; + regexCheck = std::regex(regexp.substr(6)); + } - for (auto& w : g_pCompositor->m_lWindows) { - if (!w.m_bIsMapped || w.m_bHidden) + for (auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_bHidden) continue; - const auto windowClass = g_pXWaylandManager->getAppIDClass(&w); + if (titleRegex) { + const auto windowTitle = g_pXWaylandManager->getTitle(w.get()); + if (!std::regex_search(windowTitle, regexCheck)) + continue; + } + else { + const auto windowClass = g_pXWaylandManager->getAppIDClass(w.get()); + if (!std::regex_search(windowClass, regexCheck)) + continue; + } - if (!std::regex_search(windowClass, classCheck)) - continue; + Debug::log(LOG, "Focusing to window name: %s", w->m_szTitle.c_str()); - Debug::log(LOG, "Focusing to window name: %s", w.m_szTitle.c_str()); + changeworkspace(std::to_string(w->m_iWorkspaceID)); - changeworkspace(std::to_string(w.m_iWorkspaceID)); + g_pCompositor->focusWindow(w.get()); - g_pCompositor->focusWindow(&w); - - const auto MIDPOINT = w.m_vRealPosition.goalv() + w.m_vRealSize.goalv() / 2.f; + const auto MIDPOINT = w->m_vRealPosition.goalv() + w->m_vRealSize.goalv() / 2.f; wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, MIDPOINT.x, MIDPOINT.y); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index c9132a11..31498677 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -33,6 +33,7 @@ private: inline static std::string m_szCurrentSelectedSubmap = ""; bool handleInternalKeybinds(xkb_keysym_t); + bool handleVT(xkb_keysym_t); // -------------- Dispatchers -------------- // static void killActive(std::string); @@ -60,7 +61,7 @@ private: static void resizeActive(std::string); static void moveActive(std::string); static void circleNext(std::string); - static void focusWindowByClass(std::string); + static void focusWindow(std::string); static void setSubmap(std::string); friend class CCompositor; diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 65f5ddd8..48687163 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -42,9 +42,6 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) } void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) { - if (pWindow == g_pCompositor->m_pLastWindow) - return; - if (pWindow->m_bIsX11) { if (pWindow->m_uSurface.xwayland->minimized) wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false); @@ -146,8 +143,10 @@ bool CHyprXWaylandManager::shouldBeFloated(CWindow* pWindow) { if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"]) + pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || + pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"]) { + pWindow->m_bNoInitialFocus = true; return true; } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 4019a188..94d4b8c8 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -37,6 +37,13 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } Vector2D mouseCoords = getMouseCoordsInternal(); + const auto MOUSECOORDSFLOORED = mouseCoords.floor(); + + if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored) + return; + + m_vLastCursorPosFloored = MOUSECOORDSFLOORED; + const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); bool didConstraintOnCursor = false; @@ -110,10 +117,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { Vector2D surfaceCoords; Vector2D surfacePos = Vector2D(-1337, -1337); CWindow* pFoundWindow = nullptr; + SLayerSurface* pFoundLayerSurface = nullptr; // overlay is above fullscreen if (!foundSurface) - foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords); + foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface); // then, we check if the workspace doesnt have a fullscreen window const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); @@ -123,10 +131,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { surfacePos = pFoundWindow->m_vRealPosition.vec(); // only check floating because tiled cant be over fullscreen - for (auto w = g_pCompositor->m_lWindows.rbegin(); w != g_pCompositor->m_lWindows.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 && w->m_bCreatedOverFullscreen) || (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) { - pFoundWindow = &(*w); + for (auto w = g_pCompositor->m_vWindows.rbegin(); w != g_pCompositor->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 && (*w)->m_bCreatedOverFullscreen) || ((*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden) { + pFoundWindow = (*w).get(); if (!pFoundWindow->m_bIsX11) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); @@ -141,11 +149,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } if (!foundSurface) - foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords); + foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); // then windows if (!foundSurface) { - pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); + if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) + pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + else + pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); + if (pFoundWindow) { if (!pFoundWindow->m_bIsX11) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); @@ -158,13 +170,16 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // then surfaces below if (!foundSurface) - foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &surfaceCoords); + foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &surfaceCoords, &pFoundLayerSurface); if (!foundSurface) - foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords); + foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); if (!foundSurface) { - wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor); + if (m_ecbClickBehavior == CLICKMODE_KILL) + wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor); + else + wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor); wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat); @@ -199,7 +214,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } else { g_pCompositor->focusWindow(pFoundWindow, foundSurface); } - } else + } else if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive) g_pCompositor->focusSurface(foundSurface); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); @@ -211,10 +226,70 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) { m_tmrLastCursorMovement.reset(); + switch (m_ecbClickBehavior) { + case CLICKMODE_DEFAULT: + processMouseDownNormal(e); + break; + case CLICKMODE_KILL: + processMouseDownKill(e); + break; + default: + break; + } +} + +void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e) { + if (!g_pHyprRenderer->shouldRenderCursor()) + return; + + if (!e->surface) { + g_pHyprRenderer->m_bWindowRequestedCursorHide = true; + } else { + g_pHyprRenderer->m_bWindowRequestedCursorHide = false; + } + + if (m_ecbClickBehavior == CLICKMODE_KILL) { + wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor); + return; + } + + if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, e->surface, e->hotspot_x, e->hotspot_y); +} + +eClickBehaviorMode CInputManager::getClickMode() { + return m_ecbClickBehavior; +} + +void CInputManager::setClickMode(eClickBehaviorMode mode) { + switch (mode) { + case CLICKMODE_DEFAULT: + Debug::log(LOG, "SetClickMode: DEFAULT"); + m_ecbClickBehavior = CLICKMODE_DEFAULT; + wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor); + break; + + case CLICKMODE_KILL: + Debug::log(LOG, "SetClickMode: KILL"); + m_ecbClickBehavior = CLICKMODE_KILL; + + // remove constraints + g_pCompositor->m_sSeat.mouse->constraintActive = false; + refocus(); + + // set cursor + wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor); + break; + default: + break; + } +} + +void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat); - if (!PKEYBOARD) { // ??? - Debug::log(ERR, "No active keyboard in onMouseButton??"); + if (!PKEYBOARD) { // ??? + Debug::log(ERR, "No active keyboard in processMouseDownNormal??"); return; } @@ -242,7 +317,7 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) { currentlyDraggedWindow = nullptr; dragButton = -1; } - + break; } @@ -250,7 +325,30 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) { if (g_pCompositor->doesSeatAcceptInput(g_pCompositor->m_pLastFocus)) { wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e->time_msec, e->button, e->state); } - +} + +void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) { + switch (e->state) { + case WLR_BUTTON_PRESSED: { + const auto PWINDOW = g_pCompositor->m_pLastWindow; + + if (!g_pCompositor->windowValidMapped(PWINDOW)){ + Debug::log(ERR, "Cannot kill invalid window!"); + break; + } + + // kill the mf + kill(PWINDOW->getPID(), SIGKILL); + break; + } + case WLR_BUTTON_RELEASED: + break; + default: + break; + } + + // reset click behavior mode + m_ecbClickBehavior = CLICKMODE_DEFAULT; } void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { @@ -276,16 +374,15 @@ Vector2D CInputManager::getMouseCoordsInternal() { } void CInputManager::newKeyboard(wlr_input_device* keyboard) { - m_lKeyboards.push_back(SKeyboard()); - - const auto PNEWKEYBOARD = &m_lKeyboards.back(); + const auto PNEWKEYBOARD = &m_lKeyboards.emplace_back(); PNEWKEYBOARD->keyboard = keyboard; - const auto REPEATRATE = g_pConfigManager->getInt("input:repeat_rate"); - const auto REPEATDELAY = g_pConfigManager->getInt("input:repeat_delay"); - - wlr_keyboard_set_repeat_info(keyboard->keyboard, std::max(0, REPEATRATE), std::max(0, REPEATDELAY)); + try { + PNEWKEYBOARD->name = std::string(keyboard->name); + } catch (std::exception& e) { + 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"); @@ -308,20 +405,37 @@ void CInputManager::setKeyboardLayout() { } void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { + const auto HASCONFIG = g_pConfigManager->deviceConfigExists(pKeyboard->name); ASSERT(pKeyboard); - const auto RULES = g_pConfigManager->getString("input:kb_rules"); - const auto MODEL = g_pConfigManager->getString("input:kb_model"); - const auto LAYOUT = g_pConfigManager->getString("input:kb_layout"); - const auto VARIANT = g_pConfigManager->getString("input:kb_variant"); - const auto OPTIONS = g_pConfigManager->getString("input:kb_options"); + 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"); - if (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; + const auto NUMLOCKON = HASCONFIG ? g_pConfigManager->getDeviceInt(pKeyboard->name, "numlock_by_default") : g_pConfigManager->getInt("input:numlock_by_default"); + + const auto RULES = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_rules") : g_pConfigManager->getString("input:kb_rules"); + const auto MODEL = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_model") : g_pConfigManager->getString("input:kb_model"); + const auto LAYOUT = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_layout") : g_pConfigManager->getString("input:kb_layout"); + const auto VARIANT = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_variant") : g_pConfigManager->getString("input:kb_variant"); + 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)) { + Debug::log(LOG, "Not applying config to keyboard, it did not change."); + return; + } + } catch (std::exception& e) { + // can be libc errors for null std::string + // we can ignore those and just apply } + wlr_keyboard_set_repeat_info(pKeyboard->keyboard->keyboard, std::max(0, REPEATRATE), std::max(0, REPEATDELAY)); + + pKeyboard->repeatDelay = REPEATDELAY; + pKeyboard->repeatRate = REPEATRATE; + pKeyboard->numlockOn = NUMLOCKON; + xkb_rule_names rules = { .rules = RULES.c_str(), .model = MODEL.c_str(), @@ -355,7 +469,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { wlr_keyboard_modifiers wlrMods = {0}; - if (g_pConfigManager->getInt("input:numlock_by_default") == 1) { + if (NUMLOCKON == 1) { // lock numlock const auto IDX = xkb_map_mod_get_index(KEYMAP, XKB_MOD_NAME_NUM); @@ -378,37 +492,44 @@ void CInputManager::newMouse(wlr_input_device* mouse) { const auto PMOUSE = &m_lMice.back(); PMOUSE->mouse = mouse; + try { + PMOUSE->name = std::string(mouse->name); + } catch(std::exception& e) { + Debug::log(ERR, "Mouse had no name???"); // logic error + } + + const auto HASCONFIG = g_pConfigManager->deviceConfigExists(PMOUSE->name); if (wlr_input_device_is_libinput(mouse)) { const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(mouse); - if (g_pConfigManager->getInt("input:touchpad:clickfinger_behavior") == 0) // toggle software buttons or clickfinger + if ((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "clickfinger_behavior") : g_pConfigManager->getInt("input:touchpad:clickfinger_behavior")) == 0) // toggle software buttons or clickfinger libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS); else libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); if (libinput_device_config_middle_emulation_is_available(LIBINPUTDEV)) { // middleclick on r+l mouse button pressed - if (g_pConfigManager->getInt("input:touchpad:middle_button_emulation") == 1) + if ((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "middle_button_emulation") : g_pConfigManager->getInt("input:touchpad:middle_button_emulation")) == 1) libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED); else libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); } if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop) - if (g_pConfigManager->getInt("input:touchpad:tap-to-click") == 1) + 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); if (libinput_device_config_scroll_has_natural_scroll(LIBINPUTDEV)) { double w = 0, h = 0; if (libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(LIBINPUTDEV, &w, &h) == 0) // pointer with size is a touchpad - libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, g_pConfigManager->getInt("input:touchpad:natural_scroll")); + libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, (HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "natural_scroll") : g_pConfigManager->getInt("input:touchpad:natural_scroll"))); else - libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, g_pConfigManager->getInt("input:natural_scroll")); + libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, (HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "natural_scroll") : g_pConfigManager->getInt("input:natural_scroll"))); } if (libinput_device_config_dwt_is_available(LIBINPUTDEV)) { - const auto DWT = static_cast(g_pConfigManager->getInt("input:touchpad:disable_while_typing") != 0); + const auto DWT = static_cast((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "disable_while_typing") : g_pConfigManager->getInt("input:touchpad:disable_while_typing")) != 0); libinput_device_config_dwt_set_enabled(LIBINPUTDEV, DWT); } } @@ -497,9 +618,12 @@ void CInputManager::updateDragIcon() { switch (g_pInputManager->m_sDrag.dragIcon->drag->grab_type) { case WLR_DRAG_GRAB_KEYBOARD: break; - case WLR_DRAG_GRAB_KEYBOARD_POINTER: + case WLR_DRAG_GRAB_KEYBOARD_POINTER: { + wlr_box box = {g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4}; + g_pHyprRenderer->damageBox(&box); g_pInputManager->m_sDrag.pos = g_pInputManager->getMouseCoordsInternal(); break; + } default: break; } diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 06e6cb07..1a50c585 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -6,6 +6,11 @@ #include "../../Window.hpp" #include "../../helpers/Timer.hpp" +enum eClickBehaviorMode { + CLICKMODE_DEFAULT = 0, + CLICKMODE_KILL +}; + class CInputManager { public: @@ -32,6 +37,10 @@ public: void updateDragIcon(); void updateCapabilities(wlr_input_device*); + void setClickMode(eClickBehaviorMode); + eClickBehaviorMode getClickMode(); + void processMouseRequest(wlr_seat_pointer_request_set_cursor_event*); + // for dragging floating windows CWindow* currentlyDraggedWindow = nullptr; @@ -58,6 +67,13 @@ public: private: + // for click behavior override + eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT; + Vector2D m_vLastCursorPosFloored = Vector2D(); + + void processMouseDownNormal(wlr_pointer_button_event* e); + void processMouseDownKill(wlr_pointer_button_event* e); + uint32_t m_uiCapabilities = 0; void mouseMoveUnified(uint32_t, bool refocus = false); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 4285d06b..6a62e58e 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -4,6 +4,12 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { const auto PNEWTABLET = &m_lTablets.emplace_back(); + try { + PNEWTABLET->name = std::string(pDevice->name); + } catch (std::exception& e) { + Debug::log(ERR, "Tablet had no name???"); // logic error + } + PNEWTABLET->wlrTablet = pDevice->tablet; PNEWTABLET->wlrDevice = pDevice; PNEWTABLET->wlrTabletV2 = wlr_tablet_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice); @@ -151,6 +157,12 @@ STabletTool* CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) { void CInputManager::newTabletPad(wlr_input_device* pDevice) { const auto PNEWPAD = &m_lTabletPads.emplace_back(); + try { + PNEWPAD->name = std::string(pDevice->name); + } catch (std::exception& e) { + Debug::log(ERR, "Pad had no name???"); // logic error + } + 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) { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index e44e108b..793901aa 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -81,6 +81,12 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); + prog = createProgram(QUADVERTSRC, FRAGBORDER1); + m_shBORDER1.program = prog; + m_shBORDER1.proj = glGetUniformLocation(prog, "proj"); + m_shBORDER1.posAttrib = glGetAttribLocation(prog, "pos"); + m_shBORDER1.texAttrib = glGetAttribLocation(prog, "texcoord"); + Debug::log(LOG, "Shaders initialized successfully."); // End shaders @@ -138,7 +144,9 @@ void CHyprOpenGLImpl::begin(SMonitor* pMonitor, pixman_region32_t* pDamage, bool glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - wlr_matrix_projection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: this is deprecated + matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + + m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -146,22 +154,22 @@ void CHyprOpenGLImpl::begin(SMonitor* pMonitor, pixman_region32_t* pDamage, bool m_iWLROutputFb = m_iCurrentOutputFb; // ensure a framebuffer for the monitor exists - if (m_mMonitorRenderResources.find(pMonitor) == m_mMonitorRenderResources.end() || m_mMonitorRenderResources[pMonitor].primaryFB.m_Size != pMonitor->vecPixelSize) { - m_mMonitorRenderResources[pMonitor].stencilTex.allocate(); + if (m_mMonitorRenderResources.find(pMonitor) == m_mMonitorRenderResources.end() || m_RenderData.pCurrentMonData->primaryFB.m_Size != pMonitor->vecPixelSize) { + m_RenderData.pCurrentMonData->stencilTex.allocate(); - m_mMonitorRenderResources[pMonitor].primaryFB.m_pStencilTex = &m_mMonitorRenderResources[pMonitor].stencilTex; - m_mMonitorRenderResources[pMonitor].mirrorFB.m_pStencilTex = &m_mMonitorRenderResources[pMonitor].stencilTex; - m_mMonitorRenderResources[pMonitor].mirrorSwapFB.m_pStencilTex = &m_mMonitorRenderResources[pMonitor].stencilTex; + m_RenderData.pCurrentMonData->primaryFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_mMonitorRenderResources[pMonitor].primaryFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - m_mMonitorRenderResources[pMonitor].mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - m_mMonitorRenderResources[pMonitor].mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + m_RenderData.pCurrentMonData->primaryFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); createBGTextureForMonitor(pMonitor); } // bind the primary Hypr Framebuffer - m_mMonitorRenderResources[pMonitor].primaryFB.bind(); + m_RenderData.pCurrentMonData->primaryFB.bind(); m_RenderData.pDamage = pDamage; @@ -180,7 +188,7 @@ void CHyprOpenGLImpl::end() { m_bEndFrame = true; - renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex, &monbox, 255.f, 0); + renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0); m_bEndFrame = false; } @@ -277,11 +285,11 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; // Rounded corners - glUniform2f(glGetUniformLocation(m_shQUAD.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(glGetUniformLocation(m_shQUAD.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); - glUniform2f(glGetUniformLocation(m_shQUAD.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(glGetUniformLocation(m_shQUAD.program, "radius"), round); - glUniform1i(glGetUniformLocation(m_shQUAD.program, "primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0)); + glUniform2f(m_shQUAD.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shQUAD.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(m_shQUAD.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(m_shQUAD.getUniformLocation("radius"), round); + glUniform1i(m_shQUAD.getUniformLocation("primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0)); glVertexAttribPointer(m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(m_shQUAD.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -309,15 +317,15 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha renderTexture(CTexture(tex), pBox, alpha, round); } -void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool border, bool allowPrimary) { +void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool allowPrimary) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, border, false, allowPrimary); + renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, false, allowPrimary); scissor((wlr_box*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool border, 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 allowPrimary) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); @@ -351,23 +359,6 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b RASSERT(false, "tex.m_iTarget unsupported!"); } - // stencil for when we want a border - if (border) { - glClearStencil(0); - glClear(GL_STENCIL_BUFFER_BIT); - - glEnable(GL_STENCIL_TEST); - - glStencilFunc(GL_ALWAYS, 1, -1); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - - // hacky fix to fix broken borders. - // TODO: this is kinda slow... question mark? - renderRect(pBox, CColor(0, 0, 0, 0), round); - - glDisable(GL_STENCIL_TEST); - } - glActiveTexture(GL_TEXTURE0); glBindTexture(tex.m_iTarget, tex.m_iTexID); @@ -389,11 +380,11 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; // Rounded corners - glUniform2f(glGetUniformLocation(shader->program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(glGetUniformLocation(shader->program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); - glUniform2f(glGetUniformLocation(shader->program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(glGetUniformLocation(shader->program, "radius"), round); - glUniform1i(glGetUniformLocation(shader->program, "primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !border && !noAA)); + glUniform2f(shader->getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(shader->getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(shader->getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(shader->getUniformLocation("radius"), round); + glUniform1i(shader->getUniformLocation("primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA)); glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -421,30 +412,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b } } - if (border) { - glEnable(GL_STENCIL_TEST); - - glStencilFunc(GL_EQUAL, 1, -1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } - glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); glBindTexture(tex.m_iTarget, 0); - - // if border draw - // we dont disable stencil here if we havent touched it. - // some other func might be using it. - if (border) { - auto BORDERCOL = m_pCurrentWindow->m_cRealBorderColor.col(); - static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; - BORDERCOL.a *= alpha / 255.f; - renderBorder(pBox, BORDERCOL, *PBORDERSIZE, round); - glStencilMask(-1); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - glDisable(GL_STENCIL_TEST); - } } // This probably isn't the fastest @@ -478,10 +449,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p wlr_region_expand(&damage, &damage, pow(2, *PBLURPASSES) * *PBLURSIZE); // helper - const auto PMIRRORFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB; - const auto PMIRRORSWAPFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorSwapFB; + const auto PMIRRORFB = &m_RenderData.pCurrentMonData->mirrorFB; + const auto PMIRRORSWAPFB = &m_RenderData.pCurrentMonData->mirrorSwapFB; - CFramebuffer* currentRenderToFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB; + CFramebuffer* currentRenderToFB = &m_RenderData.pCurrentMonData->primaryFB; // declare the draw func auto drawPass = [&](CShader* pShader, pixman_region32_t* pDamage) { @@ -500,11 +471,11 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p // prep two shaders glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); - glUniform1f(glGetUniformLocation(pShader->program, "radius"), *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a + glUniform1f(pShader->getUniformLocation("radius"), *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a if (pShader == &m_shBLUR1) - glUniform2f(glGetUniformLocation(m_shBLUR1.program, "halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); + glUniform2f(m_shBLUR1.getUniformLocation("halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); else - glUniform2f(glGetUniformLocation(m_shBLUR2.program, "halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f)); + glUniform2f(m_shBLUR2.getUniformLocation("halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f)); glUniform1i(pShader->tex, 0); glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -534,7 +505,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p // draw the things. // first draw is prim -> mirr PMIRRORFB->bind(); - glBindTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex.m_iTarget, m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex.m_iTexID); + glBindTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTarget, m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTexID); // damage region will be scaled, make a temp pixman_region32_t tempDamage; @@ -566,14 +537,14 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p return currentRenderToFB; } -void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round, bool border) { +void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; static auto* const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue; if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) { - renderTexture(tex, pBox, a, round, false, border, true); + renderTexture(tex, pBox, a, round, false, true); return; } @@ -596,7 +567,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, } if (!pixman_region32_not_empty(&inverseOpaque)) { - renderTexture(tex, pBox, a, round, false, border); // reject blurring a fully opaque window + renderTexture(tex, pBox, a, round, false); // reject blurring a fully opaque window return; } @@ -606,7 +577,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, pixman_region32_fini(&inverseOpaque); // bind primary - m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.bind(); + m_RenderData.pCurrentMonData->primaryFB.bind(); // make a stencil for rounded corners to work with blur scissor((wlr_box*)nullptr); // allow the entire window and stencil to render @@ -630,7 +601,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, if (pixman_region32_not_empty(&damage)) { // render our great blurred FB static auto *const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue; - renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, false, true); + renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, true); // render the window, but clear stencil glClearStencil(0); @@ -638,36 +609,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, // draw window glDisable(GL_STENCIL_TEST); - renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true, true); - glEnable(GL_STENCIL_TEST); - - // prep stencil for border - glStencilFunc(GL_ALWAYS, 1, -1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - if (border) { - // hacky fix to fix broken borders. - // TODO: this is kinda slow... question mark? - renderRectWithDamage(pBox, CColor(0,0,0,0), &damage, round); - } - - // then stop - glStencilFunc(GL_EQUAL, 1, -1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true); } - // disable the stencil (if no border), finalize everything - if (!border) { - glStencilMask(-1); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - } else { - auto BORDERCOL = m_pCurrentWindow->m_cRealBorderColor.col(); - BORDERCOL.a *= a / 255.f; - static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; - renderBorder(pBox, BORDERCOL, *PBORDERSIZE, round); - } - - glDisable(GL_STENCIL_TEST); + glStencilMask(-1); + glStencilFunc(GL_ALWAYS, 1, 0xFF); pixman_region32_fini(&damage); scissor((wlr_box*)nullptr); } @@ -679,23 +625,67 @@ void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) { counter++; } -void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int thick, int round) { +void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); - // this method assumes a set stencil and scaled box - box->x -= thick; - box->y -= thick; - box->width += 2 * thick; - box->height += 2 * thick; + static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; + static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; - round += thick; // cuz yeah + // adjust box + box->x -= *PBORDERSIZE; + box->y -= *PBORDERSIZE; + box->width += 2 * *PBORDERSIZE; + box->height += 2 * *PBORDERSIZE; - // only draw on non-stencild. - glStencilFunc(GL_NOTEQUAL, 1, -1); + round += *PBORDERSIZE; - // draw a rounded rect - renderRect(box, col, round); + float matrix[9]; + wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here + + float glMatrix[9]; + wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix); + + wlr_matrix_transpose(glMatrix, glMatrix); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glUseProgram(m_shBORDER1.program); + + glUniformMatrix3fv(m_shBORDER1.proj, 1, GL_FALSE, glMatrix); + glUniform4f(m_shBORDER1.getUniformLocation("color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f); + + const auto TOPLEFT = Vector2D(round, round); + const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round); + const auto FULLSIZE = Vector2D(box->width, box->height); + + glUniform2f(m_shBORDER1.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shBORDER1.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(m_shBORDER1.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(m_shBORDER1.getUniformLocation("radius"), round); + glUniform1f(m_shBORDER1.getUniformLocation("thick"), *PBORDERSIZE); + glUniform1i(m_shBORDER1.getUniformLocation("primitiveMultisample"), *PMULTISAMPLE); + + glVertexAttribPointer(m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + + glEnableVertexAttribArray(m_shBORDER1.posAttrib); + glEnableVertexAttribArray(m_shBORDER1.texAttrib); + + if (pixman_region32_not_empty(m_RenderData.pDamage)) { + PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { + const auto RECT = RECTSARR[i]; + scissor(&RECT); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + glDisableVertexAttribArray(m_shBORDER1.posAttrib); + glDisableVertexAttribArray(m_shBORDER1.texAttrib); + + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { @@ -744,7 +734,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { clear(CColor(0, 0, 0, 0)); // JIC wlr_box fullMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; - renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex, &fullMonBox, 255.f, 0); + renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &fullMonBox, 255.f, 0); // restore original fb #ifndef GLES2 @@ -823,12 +813,13 @@ void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) { wlr_box windowBox; // some mafs to figure out the correct box - Vector2D scaleXY = Vector2D((PWINDOW->m_vRealSize.vec().x / PWINDOW->m_vOriginalClosedSize.x), (PWINDOW->m_vRealSize.vec().y / PWINDOW->m_vOriginalClosedSize.y)); + // the originalClosedPos is relative to the monitor's pos + Vector2D scaleXY = Vector2D((PMONITOR->scale * PWINDOW->m_vRealSize.vec().x / (PWINDOW->m_vOriginalClosedSize.x * PMONITOR->scale)), (PMONITOR->scale * PWINDOW->m_vRealSize.vec().y / (PWINDOW->m_vOriginalClosedSize.y * PMONITOR->scale))); windowBox.width = PMONITOR->vecPixelSize.x * scaleXY.x; windowBox.height = PMONITOR->vecPixelSize.y * scaleXY.y; - windowBox.x = (PWINDOW->m_vRealPosition.vec().x - PMONITOR->vecPosition.x) - ((PWINDOW->m_vOriginalClosedPos.x - PMONITOR->vecPosition.x) * scaleXY.x); - windowBox.y = (PWINDOW->m_vRealPosition.vec().y - PMONITOR->vecPosition.y) - ((PWINDOW->m_vOriginalClosedPos.y - PMONITOR->vecPosition.y) * scaleXY.y); + windowBox.x = ((PWINDOW->m_vRealPosition.vec().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - ((PWINDOW->m_vOriginalClosedPos.x * PMONITOR->scale) * scaleXY.x); + windowBox.y = ((PWINDOW->m_vRealPosition.vec().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - ((PWINDOW->m_vOriginalClosedPos.y * PMONITOR->scale) * scaleXY.y); pixman_region32_t fakeDamage; pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); @@ -870,7 +861,6 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl static auto *const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue; static auto *const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue; - static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4); @@ -891,20 +881,19 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl glUseProgram(m_shSHADOW.program); glUniformMatrix3fv(m_shSHADOW.proj, 1, GL_FALSE, glMatrix); - glUniform4f(glGetUniformLocation(m_shSHADOW.program, "color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a); + glUniform4f(m_shSHADOW.getUniformLocation("color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a); const auto TOPLEFT = Vector2D(range + round, range + round); const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); const auto FULLSIZE = Vector2D(box->width, box->height); // Rounded corners - glUniform2f(glGetUniformLocation(m_shSHADOW.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(glGetUniformLocation(m_shSHADOW.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); - glUniform2f(glGetUniformLocation(m_shSHADOW.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(glGetUniformLocation(m_shSHADOW.program, "radius"), range + round); - glUniform1f(glGetUniformLocation(m_shSHADOW.program, "range"), range); - glUniform1f(glGetUniformLocation(m_shSHADOW.program, "shadowPower"), SHADOWPOWER); - glUniform1i(glGetUniformLocation(m_shSHADOW.program, "ignoreWindow"), *PSHADOWIGNOREWINDOW); + glUniform2f(m_shSHADOW.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shSHADOW.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(m_shSHADOW.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(m_shSHADOW.getUniformLocation("radius"), range + round); + glUniform1f(m_shSHADOW.getUniformLocation("range"), range); + glUniform1f(m_shSHADOW.getUniformLocation("shadowPower"), SHADOWPOWER); glVertexAttribPointer(m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 9d6e098d..292eba36 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -29,17 +29,6 @@ inline const float fanVertsFull[] = { -1.0f, 1.0f }; -struct SCurrentRenderData { - SMonitor* pMonitor = nullptr; - float projection[9]; - - pixman_region32_t* pDamage = nullptr; - - bool renderingPrimarySurface = false; - Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); - Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); -}; - struct SMonitorRenderData { CFramebuffer primaryFB; CFramebuffer mirrorFB; @@ -48,6 +37,19 @@ struct SMonitorRenderData { CTexture stencilTex; }; +struct SCurrentRenderData { + SMonitor* pMonitor = nullptr; + float projection[9]; + + SMonitorRenderData* pCurrentMonData = nullptr; + + pixman_region32_t* pDamage = nullptr; + + bool renderingPrimarySurface = false; + Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); + Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); +}; + class CHyprOpenGLImpl { public: @@ -59,9 +61,10 @@ 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 border = false, bool allowPrimary = false); - void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool border = false); + void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowPrimary = 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); void makeWindowSnapshot(CWindow*); void makeLayerSnapshot(SLayerSurface*); @@ -101,13 +104,14 @@ private: bool m_bEndFrame = false; // Shaders - SQuad m_shQUAD; + CShader m_shQUAD; CShader m_shRGBA; CShader m_shRGBX; CShader m_shEXT; CShader m_shBLUR1; CShader m_shBLUR2; CShader m_shSHADOW; + CShader m_shBORDER1; // GLuint createProgram(const std::string&, const std::string&); @@ -117,8 +121,7 @@ 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 border = false, bool noAA = false, bool allowPrimary = false); - void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0); + 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); }; 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 f7328997..eaa3cd90 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -27,7 +27,13 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { if (RDATA->surface && surface == RDATA->surface) { g_pHyprOpenGL->m_RenderData.renderingPrimarySurface = true; - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->decorate); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding); + + if (RDATA->decorate) { + auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col(); + col.a *= RDATA->fadeAlpha * RDATA->alpha / 255.f; + g_pHyprOpenGL->renderBorder(&windowBox, col, rounding); + } } else g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false, false); @@ -68,11 +74,11 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) { if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID)) return true; - for (auto& m : g_pCompositor->m_lMonitors) { - if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m.ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) + for (auto& m : g_pCompositor->m_vMonitors) { + if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) return true; - if (m.specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) + if (m->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) return true; } @@ -82,37 +88,37 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) { void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) { CWindow* pWorkspaceWindow = nullptr; - for (auto& w : g_pCompositor->m_lWindows) { - if (w.m_iWorkspaceID != pWorkspace->m_iID || !w.m_bIsFullscreen) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen) continue; // found it! - renderWindow(&w, pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL); + renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL); - pWorkspaceWindow = &w; + pWorkspaceWindow = w.get(); } // then render windows over fullscreen - for (auto& w : g_pCompositor->m_lWindows) { - if (w.m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || !w.m_bCreatedOverFullscreen || !w.m_bIsMapped) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || !w->m_bCreatedOverFullscreen || !w->m_bIsMapped) continue; - renderWindow(&w, pMonitor, time, true); + renderWindow(w.get(), pMonitor, time, true); } // and then special windows - for (auto& w : g_pCompositor->m_lWindows) { - if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut) + for (auto& w : g_pCompositor->m_vWindows) { + if (!g_pCompositor->windowValidMapped(w.get()) && !w->m_bFadingOut) continue; - if (w.m_iWorkspaceID != SPECIAL_WORKSPACE_ID) + if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) continue; - if (!shouldRenderWindow(&w, pMonitor)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; // render the bad boy - renderWindow(&w, pMonitor, time, true); + renderWindow(w.get(), pMonitor, time, true); } // and the overlay layers @@ -130,7 +136,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor renderDragIcon(pMonitor, time); // if correct monitor draw hyprerror - if (pMonitor == &g_pCompositor->m_lMonitors.front()) + if (pMonitor == g_pCompositor->m_vMonitors.front().get()) g_pHyprError->draw(); } @@ -155,7 +161,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* 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.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true); + 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; // apply window special data @@ -166,8 +172,8 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* g_pHyprOpenGL->m_pCurrentWindow = pWindow; - // render window decorations first - for (auto& wd : pWindow->m_dWindowDecorations) + // 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) { @@ -238,54 +244,54 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { } // Non-floating - for (auto& w : g_pCompositor->m_lWindows) { - if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) continue; - if (w.m_bIsFloating) + if (w->m_bIsFloating) continue; // floating are in the second pass - if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID) + if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) continue; // special are in the third pass - if (!shouldRenderWindow(&w, PMONITOR)) + if (!shouldRenderWindow(w.get(), PMONITOR)) continue; // render the bad boy - renderWindow(&w, PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true); } // floating on top - for (auto& w : g_pCompositor->m_lWindows) { - if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) continue; - if (!w.m_bIsFloating) + if (!w->m_bIsFloating) continue; - if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID) + if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) continue; - if (!shouldRenderWindow(&w, PMONITOR)) + if (!shouldRenderWindow(w.get(), PMONITOR)) continue; // render the bad boy - renderWindow(&w, PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true); } // and then special - for (auto& w : g_pCompositor->m_lWindows) { - if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) continue; - if (w.m_iWorkspaceID != SPECIAL_WORKSPACE_ID) + if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) continue; - if (!shouldRenderWindow(&w, PMONITOR)) + if (!shouldRenderWindow(w.get(), PMONITOR)) continue; // render the bad boy - renderWindow(&w, PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true); } // Render surfaces above windows for monitor @@ -545,14 +551,19 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) { pixman_region32_init(&damageBox); wlr_surface_get_effective_damage(pSurface, &damageBox); + if (!pixman_region32_not_empty(&damageBox)) { + pixman_region32_fini(&damageBox); + return; + } + pixman_region32_translate(&damageBox, x, y); - for (auto& m : g_pCompositor->m_lMonitors) { + for (auto& m : g_pCompositor->m_vMonitors) { double lx = 0, ly = 0; - wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m.output, &lx, &ly); + wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m->output, &lx, &ly); pixman_region32_translate(&damageBox, lx, ly); - wlr_region_scale(&damageBox, &damageBox, m.scale); - wlr_output_damage_add(m.damage, &damageBox); + wlr_region_scale(&damageBox, &damageBox, m->scale); + wlr_output_damage_add(m->damage, &damageBox); pixman_region32_translate(&damageBox, -lx, -ly); } @@ -565,39 +576,17 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) { } void CHyprRenderer::damageWindow(CWindow* pWindow) { - if (!pWindow->m_bIsFloating) { - // damage by size & pos - // TODO TEMP: revise when added shadows/etc - - wlr_box damageBox = pWindow->getFullWindowBoundingBox(); - for (auto& m : g_pCompositor->m_lMonitors) { - wlr_box fixedDamageBox = damageBox; - fixedDamageBox.x -= m.vecPosition.x; - fixedDamageBox.y -= m.vecPosition.y; - scaleBox(&fixedDamageBox, m.scale); - wlr_output_damage_add_box(m.damage, &fixedDamageBox); - } - - static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; - - if (*PLOGDAMAGE) - Debug::log(LOG, "Damage: Window floated (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); - } else { - // damage by real size & pos + border size * 2 (JIC) - wlr_box damageBox = pWindow->getFullWindowBoundingBox(); - for (auto& m : g_pCompositor->m_lMonitors) { - wlr_box fixedDamageBox = damageBox; - fixedDamageBox.x -= m.vecPosition.x; - fixedDamageBox.y -= m.vecPosition.y; - scaleBox(&fixedDamageBox, m.scale); - wlr_output_damage_add_box(m.damage, &fixedDamageBox); - } - - static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; - - if (*PLOGDAMAGE) - Debug::log(LOG, "Damage: Window tiled (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); + wlr_box damageBox = pWindow->getFullWindowBoundingBox(); + for (auto& m : g_pCompositor->m_vMonitors) { + wlr_box fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height}; + scaleBox(&fixedDamageBox, m->scale); + wlr_output_damage_add_box(m->damage, &fixedDamageBox); } + + static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; + + if (*PLOGDAMAGE) + Debug::log(LOG, "Damage: Window (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); } void CHyprRenderer::damageMonitor(SMonitor* pMonitor) { @@ -611,10 +600,10 @@ void CHyprRenderer::damageMonitor(SMonitor* pMonitor) { } void CHyprRenderer::damageBox(wlr_box* pBox) { - for (auto& m : g_pCompositor->m_lMonitors) { - wlr_box damageBox = {pBox->x - m.vecPosition.x, pBox->y - m.vecPosition.y, pBox->width, pBox->height}; - scaleBox(&damageBox, m.scale); - wlr_output_damage_add_box(m.damage, &damageBox); + for (auto& m : g_pCompositor->m_vMonitors) { + wlr_box damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; + scaleBox(&damageBox, m->scale); + wlr_output_damage_add_box(m->damage, &damageBox); } static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; @@ -638,6 +627,9 @@ void CHyprRenderer::renderDragIcon(SMonitor* pMonitor, timespec* time) { renderdata.h = g_pInputManager->m_sDrag.dragIcon->surface->current.height; wlr_surface_for_each_surface(g_pInputManager->m_sDrag.dragIcon->surface, renderSurface, &renderdata); + + wlr_box box = {g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4}; + g_pHyprRenderer->damageBox(&box); } DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& mode) { @@ -651,14 +643,23 @@ DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& return DAMAGE_TRACKING_INVALID; } -void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) { +bool CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) { Debug::log(LOG, "Applying monitor rule for %s", pMonitor->szName.c_str()); + // if it's disabled, disable and ignore + if (pMonitorRule->disabled) { + wlr_output_enable(pMonitor->output, 0); + wlr_output_commit(pMonitor->output); + + Events::listener_monitorDestroy(nullptr, pMonitor->output); + return false; + } + // Check if the rule isn't already applied if (!force && DELTALESSTHAN(pMonitor->vecPixelSize.x, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(pMonitor->vecPixelSize.y, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && pMonitor->scale == pMonitorRule->scale && DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1) && pMonitor->transform == pMonitorRule->transform) { Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str()); - return; + return true; } wlr_output_set_scale(pMonitor->output, pMonitorRule->scale); @@ -697,23 +698,32 @@ void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR } if (!found) { - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000); + pMonitor->vecSize = pMonitorRule->resolution; - if (!PREFERREDMODE) { - Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f", - (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate); - return; + if (!wlr_output_test(pMonitor->output)) { + Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); + + const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + + if (!PREFERREDMODE) { + Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f", + (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate); + return true; + } + + // Preferred is valid + wlr_output_set_mode(pMonitor->output, PREFERREDMODE); + + Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f", + pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, + PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + + pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; + pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + } else { + Debug::log(LOG, "Set a custom mode %ix%i@%2f (mode not found in monitor modes)", (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate); } - - // Preferred is valid - wlr_output_set_mode(pMonitor->output, PREFERREDMODE); - - Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f", - pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, - PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); - - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); } } else { wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000); @@ -730,7 +740,7 @@ void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR if (!wlr_output_commit(pMonitor->output)) { Debug::log(ERR, "Couldn't commit output named %s", pMonitor->output->name); - return; + return true; } int x, y; @@ -752,6 +762,8 @@ void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR // frame skip pMonitor->framesToSkip = 1; + + return true; } void CHyprRenderer::ensureCursorRenderingMode() { @@ -767,8 +779,8 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Hiding the cursor (timeout)"); - for (auto& m : g_pCompositor->m_lMonitors) - g_pHyprRenderer->damageMonitor(&m); // TODO: maybe just damage the cursor area? + for (auto& m : g_pCompositor->m_vMonitors) + g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? } else if (*PCURSORTIMEOUT > PASSEDCURSORSECONDS && !m_bHasARenderedCursor) { m_bHasARenderedCursor = true; @@ -777,8 +789,8 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Showing the cursor (timeout)"); - for (auto& m : g_pCompositor->m_lMonitors) - g_pHyprRenderer->damageMonitor(&m); // TODO: maybe just damage the cursor area? + for (auto& m : g_pCompositor->m_vMonitors) + g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? } } else { m_bHasARenderedCursor = true; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 43a241ed..ff9fd4ea 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -28,7 +28,7 @@ public: void damageBox(wlr_box*); void damageBox(const int& x, const int& y, const int& w, const int& h); void damageMonitor(SMonitor*); - void applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false); + bool applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false); bool shouldRenderWindow(CWindow*, SMonitor*); bool shouldRenderWindow(CWindow*); void ensureCursorRenderingMode(); diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp index e69de29b..96b3caf7 100644 --- a/src/render/Shader.cpp +++ b/src/render/Shader.cpp @@ -0,0 +1,13 @@ +#include "Shader.hpp" + +GLint CShader::getUniformLocation(const std::string& unif) { + const auto itpos = m_muUniforms.find(unif); + + if (itpos == m_muUniforms.end()) { + const auto unifLoc = glGetUniformLocation(program, unif.c_str()); + m_muUniforms[unif] = unifLoc; + return unifLoc; + } + + return itpos->second; +} \ No newline at end of file diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index 4d94358e..f996894b 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -1,22 +1,21 @@ #pragma once #include "../defines.hpp" - -struct SQuad { - GLuint program; - GLint proj; - GLint color; - GLint posAttrib; - GLint texAttrib; -}; +#include class CShader { public: GLuint program; GLint proj; + GLint color; GLint tex; GLint alpha; GLint posAttrib; GLint texAttrib; GLint discardOpaque; + + GLint getUniformLocation(const std::string&); + +private: + std::unordered_map m_muUniforms; }; \ No newline at end of file diff --git a/src/render/Shaders.hpp b/src/render/Shaders.hpp index ac7f9424..1849c621 100644 --- a/src/render/Shaders.hpp +++ b/src/render/Shaders.hpp @@ -1,4 +1,5 @@ #pragma once #include "shaders/Textures.hpp" -#include "shaders/Shadow.hpp" \ No newline at end of file +#include "shaders/Shadow.hpp" +#include "shaders/Border.hpp" \ No newline at end of file diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 6933e687..40051942 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -35,6 +35,17 @@ void CHyprDropShadowDecoration::damageEntire() { void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) { damageEntire(); + + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); + + const auto WORKSPACEOFFSET = PWORKSPACE ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); + + if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { + m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; + m_vLastWindowSize = pWindow->m_vRealSize.vec(); + + damageEntire(); + } } void CHyprDropShadowDecoration::draw(SMonitor* pMonitor, float a) { @@ -45,22 +56,70 @@ void CHyprDropShadowDecoration::draw(SMonitor* pMonitor, float a) { static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue; static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; + static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; + static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->strValue; if (*PSHADOWS != 1) return; // disabled - // update the extents if needed - if (*PSHADOWSIZE != m_seExtents.topLeft.x) - m_seExtents = {{*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}, {*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}}; + // get the real offset + Vector2D offset; + try { + if (const auto SPACEPOS = PSHADOWOFFSET->find(' '); SPACEPOS != std::string::npos) { + const auto X = PSHADOWOFFSET->substr(0, SPACEPOS); + const auto Y = PSHADOWOFFSET->substr(SPACEPOS + 1); - m_vLastWindowPos = m_pWindow->m_vRealPosition.vec(); - m_vLastWindowSize = m_pWindow->m_vRealSize.vec(); + if (isNumber(X, true) && isNumber(Y, true)) { + offset = Vector2D(std::stof(X), std::stof(Y)); + } + } + } catch (std::exception& e) { + return; // cannot parse + } + + // update the extents + m_seExtents = {{*PSHADOWSIZE + 2 - offset.x, *PSHADOWSIZE + 2 - offset.y}, {*PSHADOWSIZE + 2 + offset.x, *PSHADOWSIZE + 2 + offset.y}}; // draw the shadow wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4}; fullBox.x -= pMonitor->vecPosition.x; fullBox.y -= pMonitor->vecPosition.y; - + + if (fullBox.width < 1 || fullBox.height < 1) + return; // don't draw invisible shadows + + if (*PSHADOWIGNOREWINDOW) { + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + + glEnable(GL_STENCIL_TEST); + + glStencilFunc(GL_ALWAYS, 1, -1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + wlr_box windowBox = {m_vLastWindowPos.x - pMonitor->vecPosition.x, m_vLastWindowPos.y - pMonitor->vecPosition.y, m_vLastWindowSize.x, m_vLastWindowSize.y}; + + scaleBox(&windowBox, pMonitor->scale); + + if (windowBox.width < 1 || windowBox.height < 1) { + glDisable(GL_STENCIL_TEST); + return; // prevent assert failed + } + + g_pHyprOpenGL->renderRect(&windowBox, CColor(0,0,0,0), *PROUNDING); + + glStencilFunc(GL_NOTEQUAL, 1, -1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + + scaleBox(&fullBox, pMonitor->scale); g_pHyprOpenGL->renderRoundedShadow(&fullBox, *PROUNDING, *PSHADOWSIZE, a); + + if (*PSHADOWIGNOREWINDOW) { + // cleanup + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + glDisable(GL_STENCIL_TEST); + } } diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 2bb486ee..abb5d90c 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -21,14 +21,18 @@ eDecorationType CHyprGroupBarDecoration::getDecorationType() { void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { damageEntire(); - if (pWindow->m_vRealPosition.vec() != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); + + const auto WORKSPACEOFFSET = PWORKSPACE ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); + + if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { // we draw 3px above the window's border with 3px const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); m_seExtents.topLeft = Vector2D(0, BORDERSIZE + 3 + 3); m_seExtents.bottomRight = Vector2D(); - m_vLastWindowPos = pWindow->m_vRealPosition.vec(); + m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; m_vLastWindowSize = pWindow->m_vRealSize.vec(); } diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 21219b36..4066b6f3 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -16,7 +16,7 @@ struct SWindowDecorationExtents { class CWindow; struct SMonitor; -class IHyprWindowDecoration { +interface IHyprWindowDecoration { public: virtual ~IHyprWindowDecoration() = 0; diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/Border.hpp new file mode 100644 index 00000000..69f1ad5b --- /dev/null +++ b/src/render/shaders/Border.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include + +// makes a stencil without corners +inline const std::string FRAGBORDER1 = R"#( +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; +uniform float thick; +uniform int primitiveMultisample; + +float getOpacityForPixAndCorner(vec2 pix, vec2 corner) { + + if (primitiveMultisample == 0) { + float dis = distance(pix + vec2(0.5, 0.5), corner); + return dis < radius && dis > radius - thick ? 1.0 : 0.0; + } + + float distance1 = distance(pix + vec2(0.25, 0.25), corner); + float distance2 = distance(pix + vec2(0.75, 0.25), corner); + float distance3 = distance(pix + vec2(0.25, 0.75), corner); + float distance4 = distance(pix + vec2(0.75, 0.75), corner); + + float v1 = distance1 < radius && distance1 > radius - thick ? 1.0 : 0.0; + float v2 = distance2 < radius && distance2 > radius - thick ? 1.0 : 0.0; + float v3 = distance3 < radius && distance3 > radius - thick ? 1.0 : 0.0; + float v4 = distance4 < radius && distance4 > radius - thick ? 1.0 : 0.0; + + return (v1 + v2 + v3 + v4) / 4.0; +} + +void main() { + + vec2 pixCoord = fullSize * v_texcoord; + + vec4 pixColor = v_color; + + bool done = false; + + // check for edges + if (pixCoord[0] < topLeft[0]) { + if (pixCoord[1] < topLeft[1]) { + // top left + pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, topLeft + vec2(1,1)); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom left + pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(topLeft[0] + 1.0, bottomRight[1])); + done = true; + } + } else if (pixCoord[0] > bottomRight[0]) { + if (pixCoord[1] < topLeft[1]) { + // top right + pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(bottomRight[0], topLeft[1] + 1.0)); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom right + pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, bottomRight); + done = true; + } + } + + // now check for other shit + if (!done) { + // distance to all straight bb borders + float distanceT = pixCoord[1]; + float distanceB = fullSize[1] - pixCoord[1]; + float distanceL = pixCoord[0]; + float distanceR = fullSize[0] - pixCoord[0]; + + // get the smallest + float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR)); + + if (smallest > thick) { + discard; return; + } + } + + if (pixColor[3] == 0.0) { + discard; return; + } + + gl_FragColor = pixColor; +} +)#"; \ No newline at end of file diff --git a/src/render/shaders/Shadow.hpp b/src/render/shaders/Shadow.hpp index f54124fa..dca194c0 100644 --- a/src/render/shaders/Shadow.hpp +++ b/src/render/shaders/Shadow.hpp @@ -13,7 +13,6 @@ uniform vec2 fullSize; uniform float radius; uniform float range; uniform float shadowPower; -uniform int ignoreWindow; float pixAlphaRoundedDistance(float distanceToCorner) { if (distanceToCorner > radius) { @@ -75,7 +74,7 @@ void main() { } } - if (pixColor[3] == 0.0 || (ignoreWindow == 1 && pixColor[3] == originalAlpha)) { + if (pixColor[3] == 0.0) { discard; return; } diff --git a/subprojects/wlroots b/subprojects/wlroots index b89ed901..5c4384a1 160000 --- a/subprojects/wlroots +++ b/subprojects/wlroots @@ -1 +1 @@ -Subproject commit b89ed9015c3fbe8d339e9d65cf70fdca6e5645bc +Subproject commit 5c4384a1330faedf975c8b8644881d50390f3613