From 31694d4a4994d5595d884848c23af7a943e59c86 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Tue, 22 Mar 2022 16:17:18 +0100 Subject: [PATCH] Added pseudotiling --- CMakeLists.txt | 3 ++ example/hypr.conf | 1 + src/KeybindManager.cpp | 20 +++++++++++++ src/KeybindManager.hpp | 1 + src/config/ConfigManager.cpp | 22 ++++++++++---- src/events/events.cpp | 32 ++++++++++---------- src/window.cpp | 2 +- src/window.hpp | 4 +++ src/windowManager.cpp | 58 +++++++++++++++++++++++++++++++----- src/windowManager.hpp | 1 + 10 files changed, 113 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6526178..cfe3ec3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,7 @@ cmake_minimum_required(VERSION 3.4) + +set(CMAKE_CXX_COMPILER "/bin/g++") + project(Hypr VERSION 0.1 DESCRIPTION "A Modern OOP C++ Window Manager" diff --git a/example/hypr.conf b/example/hypr.conf index 93d857a..56585dc 100644 --- a/example/hypr.conf +++ b/example/hypr.conf @@ -68,6 +68,7 @@ windowrule=float,role:task_dialog windowrule=monitor 0,class:krunner windowrule=size 500 50,class:krunner windowrule=move 700 500,class:krunner +windowrule=pseudo,class:discord # keybinds bind=SUPER,R,exec,dmenu_run diff --git a/src/KeybindManager.cpp b/src/KeybindManager.cpp index 5011f68..cd9f3be 100644 --- a/src/KeybindManager.cpp +++ b/src/KeybindManager.cpp @@ -189,12 +189,17 @@ void KeybindManager::toggleActiveWindowFloating(std::string unusedArg) { const auto RESTOREACPOS = PWINDOW->getDefaultPosition(); const auto RESTOREWINID = PWINDOW->getDrawable(); const auto RESTORECANKILL = PWINDOW->getCanKill(); + const auto RESTOREPSEUDO = PWINDOW->getPseudoSize(); + const auto RESTOREISPSEUDO = PWINDOW->getIsPseudotiled(); + const auto RESTOREREALS = PWINDOW->getRealSize(); + const auto RESTOREREALP = PWINDOW->getRealPosition(); g_pWindowManager->removeWindowFromVectorSafe(PWINDOW->getDrawable()); CWindow newWindow; newWindow.setDrawable(RESTOREWINID); newWindow.setFirstOpen(false); + newWindow.setConstructed(false); g_pWindowManager->addWindowToVectorSafe(newWindow); const auto PNEWWINDOW = Events::remapWindow(RESTOREWINID, true); @@ -202,6 +207,10 @@ void KeybindManager::toggleActiveWindowFloating(std::string unusedArg) { PNEWWINDOW->setDefaultPosition(RESTOREACPOS); PNEWWINDOW->setDefaultSize(RESTOREACSIZE); PNEWWINDOW->setCanKill(RESTORECANKILL); + PNEWWINDOW->setPseudoSize(RESTOREPSEUDO); + PNEWWINDOW->setIsPseudotiled(RESTOREISPSEUDO); + PNEWWINDOW->setRealPosition(RESTOREREALP); + PNEWWINDOW->setRealSize(RESTOREREALS); } // EWMH to let everyone know @@ -215,4 +224,15 @@ void KeybindManager::toggleActiveWindowFloating(std::string unusedArg) { void KeybindManager::changeSplitRatio(std::string args) { g_pWindowManager->changeSplitRatioCurrent(args[0]); +} + +void KeybindManager::togglePseudoActive(std::string args) { + const auto PWINDOW = g_pWindowManager->getWindowFromDrawable(g_pWindowManager->LastWindow); + + if (!PWINDOW) + return; + + PWINDOW->setIsPseudotiled(!PWINDOW->getIsPseudotiled()); + + PWINDOW->setDirty(true); } \ No newline at end of file diff --git a/src/KeybindManager.hpp b/src/KeybindManager.hpp index b518f9e..4c72692 100644 --- a/src/KeybindManager.hpp +++ b/src/KeybindManager.hpp @@ -28,4 +28,5 @@ namespace KeybindManager { void toggleActiveWindowFloating(std::string args); void movetoworkspace(std::string args); void changeSplitRatio(std::string args); + void togglePseudoActive(std::string args); }; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index bc886e6..52c8491 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -125,6 +125,7 @@ void handleBind(const std::string& command, const std::string& value) { if (HANDLER == "lastworkspace") dispatcher = KeybindManager::changetolastworkspace; if (HANDLER == "togglefloating") dispatcher = KeybindManager::toggleActiveWindowFloating; if (HANDLER == "splitratio") dispatcher = KeybindManager::changeSplitRatio; + if (HANDLER == "pseudo") dispatcher = KeybindManager::togglePseudoActive; if (dispatcher && KEY != 0) KeybindManager::keybinds.push_back(Keybind(KeybindManager::modToMask(MOD), KEY, COMMAND, dispatcher)); @@ -240,6 +241,7 @@ void handleWindowRule(const std::string& command, const std::string& value) { && RULE.find("move") != 0 && RULE.find("size") != 0 && RULE.find("nointerventions") != 0 + && RULE.find("pseudo") != 0 && RULE.find("monitor") != 0) { Debug::log(ERR, "Invalid rule found: " + RULE); ConfigManager::parseError = "Invalid rule found: " + RULE; @@ -486,15 +488,23 @@ std::vector ConfigManager::getMatchingRules(xcb_window_t w) { for (auto& rule : ConfigManager::windowRules) { // check if we have a matching rule if (rule.szValue.find("class:") == 0) { - std::regex classCheck(rule.szValue.substr(strlen("class:"))); + try { + std::regex classCheck(rule.szValue.substr(strlen("class:"))); - if (!std::regex_search(PWINDOW->getClassName(), classCheck)) - continue; + if (!std::regex_search(PWINDOW->getClassName(), classCheck)) + continue; + } catch (...) { + Debug::log(ERR, "Regex error at " + rule.szValue); + } } else if (rule.szValue.find("role:") == 0) { - std::regex roleCheck(rule.szValue.substr(strlen("role:"))); + try { + std::regex roleCheck(rule.szValue.substr(strlen("role:"))); - if (!std::regex_search(PWINDOW->getRoleName(), roleCheck)) - continue; + if (!std::regex_search(PWINDOW->getRoleName(), roleCheck)) + continue; + } catch (...) { + Debug::log(ERR, "Regex error at " + rule.szValue); + } } else { continue; } diff --git a/src/events/events.cpp b/src/events/events.cpp index fee988c..f1480cb 100644 --- a/src/events/events.cpp +++ b/src/events/events.cpp @@ -213,6 +213,10 @@ CWindow* Events::remapFloatingWindow(int windowID, int forcemonitor) { Debug::log(LOG, "Rule monitor failed, rule: " + rule.szRule + "=" + rule.szValue); } } + + if (rule.szRule.find("pseudo") == 0) { + PWINDOWINARR->setIsPseudotiled(true); + } } const auto CURRENTSCREEN = forcemonitor != -1 ? forcemonitor : PMONITOR->ID; @@ -325,27 +329,14 @@ CWindow* Events::remapFloatingWindow(int windowID, int forcemonitor) { // // - // ICCCM + g_pWindowManager->getICCCMSizeHints(PWINDOWINARR); - xcb_size_hints_t sizeHints; - const auto succ = xcb_icccm_get_wm_normal_hints_reply(g_pWindowManager->DisplayConnection, xcb_icccm_get_wm_normal_hints_unchecked(g_pWindowManager->DisplayConnection, PWINDOWINARR->getDrawable()), &sizeHints, NULL); - if (succ && nextWindowCentered /* Basically means dialog */) { - - // vvv gets the max value out of the geometry, size hint, (size hint max if < screen) and size hint base. - auto NEWSIZE = Vector2D(std::max(std::max(sizeHints.width, (int32_t)PWINDOWINARR->getDefaultSize().x), std::max(sizeHints.max_width > g_pWindowManager->monitors[CURRENTSCREEN].vecSize.x ? 0 : sizeHints.max_width, sizeHints.base_width)), - std::max(std::max(sizeHints.height, (int32_t)PWINDOWINARR->getDefaultSize().y), std::max(sizeHints.max_height > g_pWindowManager->monitors[CURRENTSCREEN].vecSize.y ? 0 : sizeHints.max_height, sizeHints.base_height))); - - // clip the new size to max monitor size - NEWSIZE = Vector2D(std::clamp(NEWSIZE.x, (double)40.f, g_pWindowManager->monitors[CURRENTSCREEN].vecSize.x), - std::clamp(NEWSIZE.y, (double)40.f, g_pWindowManager->monitors[CURRENTSCREEN].vecSize.y)); - - auto DELTA = NEWSIZE - PWINDOWINARR->getDefaultSize(); + if (nextWindowCentered /* Basically means dialog */) { + auto DELTA = PWINDOWINARR->getPseudoSize() - PWINDOWINARR->getDefaultSize(); // update - PWINDOWINARR->setDefaultSize(NEWSIZE); + PWINDOWINARR->setDefaultSize(PWINDOWINARR->getPseudoSize()); PWINDOWINARR->setDefaultPosition(PWINDOWINARR->getDefaultPosition() - DELTA / 2.f); - } else if (!succ) { - Debug::log(ERR, "ICCCM Size Hints failed."); } // Check the size and pos rules @@ -453,6 +444,10 @@ CWindow* Events::remapWindow(int windowID, bool wasfloating, int forcemonitor) { Debug::log(LOG, "Rule monitor failed, rule: " + rule.szRule + "=" + rule.szValue); } } + + if (rule.szRule.find("pseudo") == 0) { + PWINDOWINARR->setIsPseudotiled(true); + } } if (g_pWindowManager->getWindowFromDrawable(g_pWindowManager->LastWindow) && forcemonitor == -1 && PMONITOR->ID != g_pWindowManager->getWindowFromDrawable(g_pWindowManager->LastWindow)->getMonitor()) { @@ -500,6 +495,8 @@ CWindow* Events::remapWindow(int windowID, bool wasfloating, int forcemonitor) { } } + g_pWindowManager->getICCCMSizeHints(PWINDOWINARR); + // Set the parent // check if lastwindow is on our workspace if (auto PLASTWINDOW = g_pWindowManager->getWindowFromDrawable(g_pWindowManager->LastWindow); (PLASTWINDOW && PLASTWINDOW->getWorkspaceID() == g_pWindowManager->activeWorkspaces[CURRENTSCREEN]) || wasfloating || (forcemonitor != -1 && forcemonitor != PMONITOR->ID)) { @@ -763,6 +760,7 @@ void Events::eventMotionNotify(xcb_generic_event_t* event) { PACTINGWINDOW->setDefaultSize(PACTINGWINDOW->getSize()); PACTINGWINDOW->setEffectiveSize(PACTINGWINDOW->getSize()); PACTINGWINDOW->setRealSize(PACTINGWINDOW->getSize()); + PACTINGWINDOW->setPseudoSize(PACTINGWINDOW->getSize()); PACTINGWINDOW->setDirty(true); } diff --git a/src/window.cpp b/src/window.cpp index c8fe9b0..31ed8c3 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,7 +1,7 @@ #include "window.hpp" #include "windowManager.hpp" -CWindow::CWindow() { this->setSplitRatio(1); this->setDockHidden(false); this->setRealBorderColor(0); this->setEffectiveBorderColor(0); this->setFirstOpen(true); this->setConstructed(false); this->setTransient(false); this->setLastUpdatePosition(Vector2D(0,0)); this->setLastUpdateSize(Vector2D(0,0)); this->setDock(false); this->setUnderFullscreen(false); this->setIsSleeping(true); this->setFirstAnimFrame(true); this->setIsAnimated(false); this->setDead(false); this->setMasterChildIndex(0); this->setMaster(false); this->setCanKill(false); this->setImmovable(false); this->setNoInterventions(false); this->setDirty(true); this->setFullscreen(false); this->setIsFloating(false); this->setParentNodeID(0); this->setChildNodeAID(0); this->setChildNodeBID(0); this->setName(""); } +CWindow::CWindow() { this->setIsPseudotiled(false); this->setSplitRatio(1); this->setDockHidden(false); this->setRealBorderColor(0); this->setEffectiveBorderColor(0); this->setFirstOpen(true); this->setConstructed(false); this->setTransient(false); this->setLastUpdatePosition(Vector2D(0,0)); this->setLastUpdateSize(Vector2D(0,0)); this->setDock(false); this->setUnderFullscreen(false); this->setIsSleeping(true); this->setFirstAnimFrame(true); this->setIsAnimated(false); this->setDead(false); this->setMasterChildIndex(0); this->setMaster(false); this->setCanKill(false); this->setImmovable(false); this->setNoInterventions(false); this->setDirty(true); this->setFullscreen(false); this->setIsFloating(false); this->setParentNodeID(0); this->setChildNodeAID(0); this->setChildNodeBID(0); this->setName(""); } CWindow::~CWindow() { } void CWindow::generateNodeID() { diff --git a/src/window.hpp b/src/window.hpp index 8a9b982..6efa376 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -108,6 +108,10 @@ public: EXPOSED_MEMBER(Children, std::vector, vec); EXPOSED_MEMBER(Transient, bool, b); + // Pseudotiling + EXPOSED_MEMBER(IsPseudotiled, bool, b); + EXPOSED_MEMBER(PseudoSize, Vector2D, vec); + private: }; \ No newline at end of file diff --git a/src/windowManager.cpp b/src/windowManager.cpp index 50e7718..34fdc35 100644 --- a/src/windowManager.cpp +++ b/src/windowManager.cpp @@ -899,21 +899,51 @@ void CWindowManager::setEffectiveSizePosUsingConfig(CWindow* pWindow) { const auto GAPSOUT = ConfigManager::getInt("gaps_out"); const auto GAPSIN = ConfigManager::getInt("gaps_in"); - pWindow->setEffectivePosition(pWindow->getPosition() + Vector2D(BORDERSIZE, BORDERSIZE)); - pWindow->setEffectiveSize(pWindow->getSize() - (Vector2D(BORDERSIZE, BORDERSIZE) * 2)); + auto TEMPEFFECTIVESIZE = pWindow->getSize(); + auto TEMPEFFECTIVEPOS = pWindow->getPosition(); const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT + MONITOR->vecReservedTopLeft.x : GAPSIN, - DISPLAYTOP ? GAPSOUT + MONITOR->vecReservedTopLeft.y : GAPSIN); + DISPLAYTOP ? GAPSOUT + MONITOR->vecReservedTopLeft.y : GAPSIN); - const auto OFFSETBOTTOMRIGHT = Vector2D( DISPLAYRIGHT ? GAPSOUT + MONITOR->vecReservedBottomRight.x : GAPSIN, + const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? GAPSOUT + MONITOR->vecReservedBottomRight.x : GAPSIN, DISPLAYBOTTOM ? GAPSOUT + MONITOR->vecReservedBottomRight.y : GAPSIN); + TEMPEFFECTIVEPOS = TEMPEFFECTIVEPOS + Vector2D(BORDERSIZE, BORDERSIZE); + TEMPEFFECTIVESIZE = TEMPEFFECTIVESIZE - (Vector2D(BORDERSIZE, BORDERSIZE) * 2); + // do gaps, set top left - pWindow->setEffectivePosition(pWindow->getEffectivePosition() + OFFSETTOPLEFT); + TEMPEFFECTIVEPOS = TEMPEFFECTIVEPOS + OFFSETTOPLEFT; // fix to old size bottom right - pWindow->setEffectiveSize(pWindow->getEffectiveSize() - OFFSETTOPLEFT); + TEMPEFFECTIVESIZE = TEMPEFFECTIVESIZE - OFFSETTOPLEFT; // set bottom right - pWindow->setEffectiveSize(pWindow->getEffectiveSize() - OFFSETBOTTOMRIGHT); + TEMPEFFECTIVESIZE = TEMPEFFECTIVESIZE - OFFSETBOTTOMRIGHT; + + if (pWindow->getIsPseudotiled()) { + float scale = 1; + + // adjust if doesnt fit + if (pWindow->getPseudoSize().x > TEMPEFFECTIVESIZE.x || pWindow->getPseudoSize().y > TEMPEFFECTIVESIZE.y) { + + if (pWindow->getPseudoSize().x > TEMPEFFECTIVESIZE.x) { + scale = TEMPEFFECTIVESIZE.x / pWindow->getPseudoSize().x; + } + + if (pWindow->getPseudoSize().y * scale > TEMPEFFECTIVESIZE.y) { + scale = TEMPEFFECTIVESIZE.y / pWindow->getPseudoSize().y; + } + + auto DELTA = TEMPEFFECTIVESIZE - pWindow->getPseudoSize() * scale; + TEMPEFFECTIVESIZE = pWindow->getPseudoSize() * scale; + TEMPEFFECTIVEPOS = TEMPEFFECTIVEPOS + DELTA / 2.f; // center + } else { + auto DELTA = TEMPEFFECTIVESIZE - pWindow->getPseudoSize(); + TEMPEFFECTIVEPOS = TEMPEFFECTIVEPOS + DELTA / 2.f; // center + TEMPEFFECTIVESIZE = pWindow->getPseudoSize(); + } + } + + pWindow->setEffectivePosition(TEMPEFFECTIVEPOS); + pWindow->setEffectiveSize(TEMPEFFECTIVESIZE); } CWindow* CWindowManager::findWindowAtCursor() { @@ -2465,4 +2495,18 @@ void CWindowManager::changeSplitRatioCurrent(const char& dir) { Debug::log(LOG, "Changed SplitRatio of " + std::to_string(PARENT->getDrawable()) + " to " + std::to_string(PARENT->getSplitRatio()) + " (" + dir + ")" ); recalcEntireWorkspace(CURRENT->getWorkspaceID()); +} + +void CWindowManager::getICCCMSizeHints(CWindow* pWindow) { + xcb_size_hints_t sizeHints; + const auto succ = xcb_icccm_get_wm_normal_hints_reply(g_pWindowManager->DisplayConnection, xcb_icccm_get_wm_normal_hints_unchecked(g_pWindowManager->DisplayConnection, pWindow->getDrawable()), &sizeHints, NULL); + + if (succ) { + auto NEWSIZE = Vector2D(std::max(std::max(sizeHints.width, (int32_t)pWindow->getDefaultSize().x), std::max(sizeHints.max_width > g_pWindowManager->monitors[pWindow->getMonitor()].vecSize.x ? 0 : sizeHints.max_width, sizeHints.base_width)), + std::max(std::max(sizeHints.height, (int32_t)pWindow->getDefaultSize().y), std::max(sizeHints.max_height > g_pWindowManager->monitors[pWindow->getMonitor()].vecSize.y ? 0 : sizeHints.max_height, sizeHints.base_height))); + + pWindow->setPseudoSize(NEWSIZE); + } else { + Debug::log(ERR, "ICCCM Size Hints failed."); + } } \ No newline at end of file diff --git a/src/windowManager.hpp b/src/windowManager.hpp index f8c04ff..971f9b7 100644 --- a/src/windowManager.hpp +++ b/src/windowManager.hpp @@ -84,6 +84,7 @@ public: void refocusWindowOnClosed(); void calculateNewWindowParams(CWindow*); + void getICCCMSizeHints(CWindow*); void fixWindowOnClose(CWindow*); void closeWindowAllChecks(int64_t);