diff --git a/README.md b/README.md index af03da5..c1d80cb 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Hypr is a Linux tiling window manager for Xorg. It's written in XCB with modern - [ ] Status bar - [ ] Floating windows support - [ ] Config system -- [ ] Workspaces +- [x] Workspaces - [ ] Moving windows / user input (e.g. fullscreening) - [ ] True lerp animations diff --git a/src/KeybindManager.cpp b/src/KeybindManager.cpp index fe6a12d..9b2f5ec 100644 --- a/src/KeybindManager.cpp +++ b/src/KeybindManager.cpp @@ -27,6 +27,12 @@ void KeybindManager::reloadAllKeybinds() { KeybindManager::keybinds.push_back(Keybind(MOD_SUPER, 0xff53 /* > */, "r", &KeybindManager::movewindow)); KeybindManager::keybinds.push_back(Keybind(MOD_SUPER, 0xff52 /* ^ */, "t", &KeybindManager::movewindow)); KeybindManager::keybinds.push_back(Keybind(MOD_SUPER, 0xff54 /* v */, "b", &KeybindManager::movewindow)); + + // workspace binds + for (int i = 0; i < 10; ++i) { + // MOD + 1-9 + KeybindManager::keybinds.push_back(Keybind(MOD_SUPER, 0x31 + i, std::to_string(i + 1), &KeybindManager::changeworkspace)); + } } unsigned int KeybindManager::modToMask(MODS mod) { @@ -105,4 +111,20 @@ void KeybindManager::call(std::string args) { void KeybindManager::movewindow(std::string arg) { g_pWindowManager->moveActiveWindowTo(arg[0]); +} + +void KeybindManager::changeworkspace(std::string arg) { + int ID = -1; + try { + ID = std::stoi(arg.c_str()); + } catch (...) { ; } + + if (ID != -1) { + Debug::log(LOG, "Changing the current workspace to " + std::to_string(ID)); + + // vvvv shouldn't be nullptr wallah + g_pWindowManager->setAllWorkspaceWindowsDirtyByID(g_pWindowManager->activeWorkspace->getID()); + g_pWindowManager->changeWorkspaceByID(ID); + g_pWindowManager->setAllWorkspaceWindowsDirtyByID(ID); + } } \ No newline at end of file diff --git a/src/KeybindManager.hpp b/src/KeybindManager.hpp index a1c9f96..9b87b8a 100644 --- a/src/KeybindManager.hpp +++ b/src/KeybindManager.hpp @@ -18,4 +18,5 @@ namespace KeybindManager { void call(std::string args); void killactive(std::string args); void movewindow(std::string args); + void changeworkspace(std::string args); }; \ No newline at end of file diff --git a/src/events/events.cpp b/src/events/events.cpp index 888a00a..cc31ee2 100644 --- a/src/events/events.cpp +++ b/src/events/events.cpp @@ -41,6 +41,7 @@ void Events::eventMapWindow(xcb_generic_event_t* event) { window.setDrawable(E->window); window.setIsFloating(false); window.setDirty(true); + window.setWorkspaceID(g_pWindowManager->activeWorkspace->getID()); // Also sets the old one g_pWindowManager->calculateNewWindowParams(&window); diff --git a/src/utilities/Workspace.hpp b/src/utilities/Workspace.hpp new file mode 100644 index 0000000..aa2e945 --- /dev/null +++ b/src/utilities/Workspace.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "../defines.hpp" + +class CWorkspace { +public: + EXPOSED_MEMBER(ID, int, i); + EXPOSED_MEMBER(LastWindow, xcb_drawable_t, i); +}; diff --git a/src/window.hpp b/src/window.hpp index c1a3d99..4095900 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -1,6 +1,7 @@ #pragma once #include "defines.hpp" +#include "utilities/Workspace.hpp" class CWindow { public: @@ -24,6 +25,9 @@ public: EXPOSED_MEMBER(Position, Vector2D, vec); EXPOSED_MEMBER(IsFloating, bool, b); EXPOSED_MEMBER(Drawable, xcb_drawable_t, i); + + // Workspace pointer + EXPOSED_MEMBER(WorkspaceID, int, i); private: diff --git a/src/windowManager.cpp b/src/windowManager.cpp index 0d0280f..5b1aa2d 100644 --- a/src/windowManager.cpp +++ b/src/windowManager.cpp @@ -28,6 +28,13 @@ void CWindowManager::setupManager() { 3, KeybindManager::modToMask(MOD_SUPER)); xcb_flush(DisplayConnection); + + // Add a workspace to the monitor + CWorkspace protoWorkspace; + protoWorkspace.setID(1); + workspaces.push_back(protoWorkspace); + activeWorkspace = &workspaces[0]; + // } bool CWindowManager::handleEvent() { @@ -70,15 +77,59 @@ bool CWindowManager::handleEvent() { // refresh and apply the parameters of all dirty windows. refreshDirtyWindows(); + // remove unused workspaces + cleanupUnusedWorkspaces(); + xcb_flush(DisplayConnection); return true; } +void CWindowManager::cleanupUnusedWorkspaces() { + std::vector temp = workspaces; + + workspaces.clear(); + + for (auto& work : temp) { + if (work.getID() != activeWorkspace->getID()) { + // check if it has any children + bool hasChildren = false; + for (auto& window : windows) { + if (window.getWorkspaceID() == work.getID()) { + hasChildren = true; + break; + } + } + + if (hasChildren) { + // Has windows opened on it. + workspaces.push_back(work); + } + } else { + // Foreground workspace + workspaces.push_back(work); + } + } +} + void CWindowManager::refreshDirtyWindows() { for(auto& window : windows) { if (window.getDirty()) { - + + // first and foremost, let's check if the window isn't on a different workspace + if (window.getWorkspaceID() != activeWorkspace->getID()) { + // Move it to hades + Values[0] = (int)1500000; // hmu when monitors actually have that many pixels + Values[1] = (int)1500000; // and we are still using xorg =) + xcb_configure_window(DisplayConnection, window.getDrawable(), XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, Values); + + // Set the size JIC. + Values[0] = (int)window.getEffectiveSize().x; + Values[1] = (int)window.getEffectiveSize().y; + xcb_configure_window(DisplayConnection, window.getDrawable(), XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, Values); + + continue; + } Values[0] = (int)window.getEffectiveSize().x; Values[1] = (int)window.getEffectiveSize().y; @@ -224,6 +275,10 @@ void CWindowManager::calculateNewWindowParams(CWindow* pWindow) { } bool CWindowManager::isNeighbor(CWindow* a, CWindow* b) { + + if (a->getWorkspaceID() != b->getWorkspaceID()) + return false; // Different workspaces + const auto POSA = a->getPosition(); const auto POSB = b->getPosition(); const auto SIZEA = a->getSize(); @@ -274,7 +329,7 @@ bool CWindowManager::canEatWindow(CWindow* a, CWindow* toEat) { }; for (auto& w : windows) { - if (w.getDrawable() == a->getDrawable() || w.getDrawable() == toEat->getDrawable()) + if (w.getDrawable() == a->getDrawable() || w.getDrawable() == toEat->getDrawable() || w.getWorkspaceID() != toEat->getWorkspaceID()) continue; if (doOverlap(&w)) @@ -335,7 +390,7 @@ CWindow* CWindowManager::getNeighborInDir(char dir) { const auto SIZEA = CURRENTWINDOW->getSize(); for (auto& w : windows) { - if (w.getDrawable() == CURRENTWINDOW->getDrawable()) + if (w.getDrawable() == CURRENTWINDOW->getDrawable() || w.getWorkspaceID() != CURRENTWINDOW->getWorkspaceID()) continue; const auto POSB = w.getPosition(); @@ -409,4 +464,39 @@ void CWindowManager::moveActiveWindowTo(char dir) { // finish by moving the cursor to the current window warpCursorTo(CURRENTWINDOW->getPosition() + CURRENTWINDOW->getSize() / 2.f); +} + +void CWindowManager::changeWorkspaceByID(int ID) { + for (auto& workspace : workspaces) { + if (workspace.getID() == ID) { + activeWorkspace = &workspace; + LastWindow = -1; + return; + } + } + + // If we are here it means the workspace is new. Let's create it. + CWorkspace newWorkspace; + newWorkspace.setID(ID); + workspaces.push_back(newWorkspace); + activeWorkspace = &workspaces[workspaces.size() - 1]; + LastWindow = -1; +} + +void CWindowManager::setAllWorkspaceWindowsDirtyByID(int ID) { + int workspaceID = -1; + for (auto& workspace : workspaces) { + if (workspace.getID() == ID) { + workspaceID = workspace.getID(); + break; + } + } + + if (workspaceID == -1) + return; + + for (auto& window : windows) { + if (window.getWorkspaceID() == workspaceID) + window.setDirty(true); + } } \ No newline at end of file diff --git a/src/windowManager.hpp b/src/windowManager.hpp index e2e1307..398f327 100644 --- a/src/windowManager.hpp +++ b/src/windowManager.hpp @@ -6,6 +6,7 @@ #include #include "KeybindManager.hpp" +#include "./utilities/Workspace.hpp" // temp config values @@ -23,6 +24,9 @@ public: std::vector windows; // windows never left. It has always been hiding amongst us. xcb_drawable_t LastWindow = -1; + std::vector workspaces; + CWorkspace* activeWorkspace = nullptr; + CWindow* getWindowFromDrawable(xcb_drawable_t); void addWindowToVectorSafe(CWindow); void removeWindowFromVectorSafe(xcb_drawable_t); @@ -39,17 +43,21 @@ public: void moveActiveWindowTo(char); void warpCursorTo(Vector2D); + void changeWorkspaceByID(int); + void setAllWorkspaceWindowsDirtyByID(int); + private: // Internal WM functions that don't have to be exposed - + CWindow* getNeighborInDir(char dir); void eatWindow(CWindow* a, CWindow* toEat); bool canEatWindow(CWindow* a, CWindow* toEat); bool isNeighbor(CWindow* a, CWindow* b); void calculateNewTileSetOldTile(CWindow* pWindow); void setEffectiveSizePosUsingConfig(CWindow* pWindow); + void cleanupUnusedWorkspaces(); }; -inline std::unique_ptr g_pWindowManager = std::make_unique(); \ No newline at end of file +inline std::unique_ptr g_pWindowManager = std::make_unique();