diff --git a/src/KeybindManager.cpp b/src/KeybindManager.cpp index 88d3d29..40f3c92 100644 --- a/src/KeybindManager.cpp +++ b/src/KeybindManager.cpp @@ -135,19 +135,29 @@ void KeybindManager::changeworkspace(std::string arg) { if (ID != -1) { Debug::log(LOG, "Changing the current workspace to " + std::to_string(ID)); + const auto PLASTWINDOW = g_pWindowManager->getWindowFromDrawable(g_pWindowManager->LastWindow); + SMonitor* MONITOR = nullptr; + if (PLASTWINDOW) { + MONITOR = g_pWindowManager->getMonitorFromWindow(PLASTWINDOW); + } else { + MONITOR = g_pWindowManager->getMonitorFromCursor(); + } + // vvvv shouldn't be nullptr wallah - g_pWindowManager->setAllWorkspaceWindowsDirtyByID(g_pWindowManager->activeWorkspace->getID()); + g_pWindowManager->setAllWorkspaceWindowsDirtyByID(g_pWindowManager->activeWorkspaces[MONITOR->ID]->getID()); g_pWindowManager->changeWorkspaceByID(ID); g_pWindowManager->setAllWorkspaceWindowsDirtyByID(ID); } } void KeybindManager::toggleActiveWindowFullscreen(std::string unusedArg) { - g_pWindowManager->setAllWorkspaceWindowsDirtyByID(g_pWindowManager->activeWorkspace->getID()); + const auto MONITOR = g_pWindowManager->getMonitorFromWindow(g_pWindowManager->getWindowFromDrawable(g_pWindowManager->LastWindow)); + + g_pWindowManager->setAllWorkspaceWindowsDirtyByID(g_pWindowManager->activeWorkspaces[MONITOR->ID]->getID()); if (auto WINDOW = g_pWindowManager->getWindowFromDrawable(g_pWindowManager->LastWindow) ; WINDOW) { WINDOW->setFullscreen(!WINDOW->getFullscreen()); - g_pWindowManager->activeWorkspace->setHasFullscreenWindow(WINDOW->getFullscreen()); + g_pWindowManager->activeWorkspaces[MONITOR->ID]->setHasFullscreenWindow(WINDOW->getFullscreen()); } } diff --git a/src/bar/Bar.cpp b/src/bar/Bar.cpp index c26c35c..760788c 100644 --- a/src/bar/Bar.cpp +++ b/src/bar/Bar.cpp @@ -123,7 +123,7 @@ int getTextWidth(std::string text, xcb_font_t font) { void CStatusBar::draw() { - if (g_pWindowManager->activeWorkspace->getHasFullscreenWindow()) + if (g_pWindowManager->activeWorkspaces[m_iMonitorID]->getHasFullscreenWindow()) return; // Do not draw a bar on a fullscreen window. xcb_rectangle_t rectangles[] = {{m_vecPosition.x, m_vecPosition.y, m_vecSize.x + m_vecPosition.x, m_vecPosition.y + m_vecSize.y}}; @@ -140,13 +140,13 @@ void CStatusBar::draw() { std::string workspaceName = std::to_string(i); - if (WORKSPACE->getID() == g_pWindowManager->activeWorkspace->getID()) { + if (WORKSPACE->getID() == g_pWindowManager->activeWorkspaces[m_iMonitorID]->getID()) { xcb_rectangle_t rectangleActive[] = { { m_vecSize.y * drawnWorkspaces, 0, m_vecSize.y, m_vecSize.y } }; xcb_poly_fill_rectangle(g_pWindowManager->DisplayConnection, m_iPixmap, m_mContexts["MEDBG"].GContext, 1, rectangleActive); } xcb_image_text_8(g_pWindowManager->DisplayConnection, workspaceName.length(), m_iPixmap, - WORKSPACE->getID() == g_pWindowManager->activeWorkspace->getID() ? m_mContexts["HITEXT"].GContext : m_mContexts["BASETEXT"].GContext, + WORKSPACE->getID() == g_pWindowManager->activeWorkspaces[m_iMonitorID]->getID() ? m_mContexts["HITEXT"].GContext : m_mContexts["BASETEXT"].GContext, m_vecSize.y * drawnWorkspaces + m_vecSize.y / 2.f - 2, m_vecSize.y - (m_vecSize.y - 10) / 2, workspaceName.c_str()); drawnWorkspaces++; diff --git a/src/bar/Bar.hpp b/src/bar/Bar.hpp index d7b5aad..975b741 100644 --- a/src/bar/Bar.hpp +++ b/src/bar/Bar.hpp @@ -13,6 +13,7 @@ class CStatusBar { public: EXPOSED_MEMBER(WindowID, xcb_window_t, i); + EXPOSED_MEMBER(MonitorID, int, i); void draw(); void setup(Vector2D, Vector2D); diff --git a/src/defines.hpp b/src/defines.hpp index 99e971f..3ced79d 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -1,14 +1,17 @@ #include #include #include +#include #include +#include +#include #include -#include #include +#include +#include #include "./helpers/Vector.hpp" - #include "./utilities/Debug.hpp" #define EXPOSED_MEMBER(var, type, prefix) \ @@ -22,4 +25,6 @@ #define EVENT(name) \ void event##name(xcb_generic_event_t* event); -#define STICKS(a, b) abs((a) - (b)) < 2 \ No newline at end of file +#define STICKS(a, b) abs((a) - (b)) < 2 + +#define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2)) \ No newline at end of file diff --git a/src/events/events.cpp b/src/events/events.cpp index 814ba9d..2c7fdd3 100644 --- a/src/events/events.cpp +++ b/src/events/events.cpp @@ -62,7 +62,9 @@ void Events::eventMapWindow(xcb_generic_event_t* event) { window.setDrawable(E->window); window.setIsFloating(false); window.setDirty(true); - window.setWorkspaceID(g_pWindowManager->activeWorkspace->getID()); + const auto CURRENTSCREEN = g_pWindowManager->getMonitorFromCursor()->ID; + window.setWorkspaceID(g_pWindowManager->activeWorkspaces[CURRENTSCREEN]->getID()); + window.setMonitor(CURRENTSCREEN); window.setDefaultPosition(Vector2D(0,0)); window.setDefaultSize(Vector2D(g_pWindowManager->Screen->width_in_pixels/2.f,g_pWindowManager->Screen->height_in_pixels/2.f)); diff --git a/src/utilities/Monitor.hpp b/src/utilities/Monitor.hpp new file mode 100644 index 0000000..f6532a6 --- /dev/null +++ b/src/utilities/Monitor.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "../defines.hpp" + +struct SMonitor { + Vector2D vecPosition = Vector2D(0,0); + Vector2D vecSize = Vector2D(0,0); + + bool hasABar = false; + bool primary = false; + + int ID = -1; + + std::string szName = ""; +}; \ No newline at end of file diff --git a/src/utilities/Workspace.hpp b/src/utilities/Workspace.hpp index 67f2382..fd7d74e 100644 --- a/src/utilities/Workspace.hpp +++ b/src/utilities/Workspace.hpp @@ -10,5 +10,7 @@ public: EXPOSED_MEMBER(ID, int, i); EXPOSED_MEMBER(LastWindow, xcb_drawable_t, i); + EXPOSED_MEMBER(Monitor, int, i); + EXPOSED_MEMBER(HasFullscreenWindow, bool, b); }; diff --git a/src/window.hpp b/src/window.hpp index 4c9cde8..554d8c1 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -35,6 +35,9 @@ public: // For floating EXPOSED_MEMBER(DefaultSize, Vector2D, vec); EXPOSED_MEMBER(DefaultPosition, Vector2D, vec); + + // Monitors + EXPOSED_MEMBER(Monitor, int, i); private: diff --git a/src/windowManager.cpp b/src/windowManager.cpp index 56b5237..08ef1ac 100644 --- a/src/windowManager.cpp +++ b/src/windowManager.cpp @@ -1,5 +1,6 @@ #include "windowManager.hpp" #include "./events/events.hpp" +#include xcb_visualtype_t* CWindowManager::setupColors() { auto depthIter = xcb_screen_allowed_depths_iterator(Screen); @@ -14,8 +15,77 @@ xcb_visualtype_t* CWindowManager::setupColors() { return nullptr; } +void CWindowManager::setupRandrMonitors() { + auto ScreenResReply = xcb_randr_get_screen_resources_current_reply(DisplayConnection, xcb_randr_get_screen_resources_current(DisplayConnection, Screen->root), NULL); + if (!ScreenResReply) { + Debug::log(ERR, "ScreenResReply NULL!"); + return; + } + + const auto MONITORNUM = xcb_randr_get_screen_resources_current_outputs_length(ScreenResReply); + auto OUTPUTS = xcb_randr_get_screen_resources_current_outputs(ScreenResReply); + + xcb_randr_get_output_info_reply_t* outputReply; + xcb_randr_get_crtc_info_reply_t* crtcReply; + + + + for (int i = 0; i < MONITORNUM; i++) { + outputReply = xcb_randr_get_output_info_reply(DisplayConnection, xcb_randr_get_output_info(DisplayConnection, OUTPUTS[i], XCB_CURRENT_TIME), NULL); + if (outputReply->crtc == XCB_NONE) + continue; + crtcReply = xcb_randr_get_crtc_info_reply(DisplayConnection, xcb_randr_get_crtc_info(DisplayConnection, outputReply->crtc, XCB_CURRENT_TIME), NULL); + if (!crtcReply) + continue; + + monitors.push_back(SMonitor()); + + monitors[i].vecPosition = Vector2D(crtcReply->x, crtcReply->y); + monitors[i].vecSize = Vector2D(crtcReply->width, crtcReply->height); + + monitors[i].ID = i; + + char* name = (char*)xcb_randr_get_output_info_name(outputReply); + int nameLen = xcb_randr_get_output_info_name_length(outputReply); + + for (int j = 0; j < nameLen; ++j) { + monitors[i].szName += name[j]; + } + } + + const auto EXTENSIONREPLY = xcb_get_extension_data(DisplayConnection, &xcb_randr_id); + if (!EXTENSIONREPLY->present) + Debug::log(ERR, "RandR extension missing"); + else { + //listen for screen change events + xcb_randr_select_input(DisplayConnection, Screen->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); + } +} + void CWindowManager::setupManager() { ConfigManager::init(); + setupRandrMonitors(); + + if (monitors.size() == 0) { + // RandR failed! + Debug::log(WARN, "RandR failed!"); + + monitors.push_back(SMonitor()); + monitors[0].vecPosition = Vector2D(0,0); + monitors[0].vecSize = Vector2D(Screen->width_in_pixels, Screen->height_in_pixels); + monitors[0].ID = 0; + monitors[0].szName = "Screen"; + } + + // TODO: get it normally. + if (monitors.size() > 1) { + monitors[1].primary = true; + monitors[1].hasABar = true; + } else { + monitors[0].primary = true; + monitors[0].hasABar = true; + } + Values[0] = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; xcb_change_window_attributes_checked(DisplayConnection, Screen->root, @@ -42,11 +112,14 @@ void CWindowManager::setupManager() { xcb_flush(DisplayConnection); - // Add a workspace to the monitor - CWorkspace protoWorkspace; - protoWorkspace.setID(1); - workspaces.push_back(protoWorkspace); - activeWorkspace = &workspaces[0]; + // Add workspaces to the monitors + for (int i = 0; i < monitors.size(); ++i) { + CWorkspace protoWorkspace; + protoWorkspace.setID(i + 1); + protoWorkspace.setMonitor(i); + workspaces.push_back(protoWorkspace); + activeWorkspaces.push_back(&workspaces[i]); + } // // init visual type, default 32 bit depth @@ -60,7 +133,12 @@ void CWindowManager::setupManager() { // ---- INIT THE BAR ---- // - statusBar.setup(Vector2D(0, 0), Vector2D(Screen->width_in_pixels, ConfigManager::getInt("bar_height"))); + for (auto& monitor : monitors) { + if (monitor.primary) { + statusBar.setup(Vector2D(monitor.vecPosition.x, monitor.vecPosition.y), Vector2D(monitor.vecSize.x, ConfigManager::getInt("bar_height"))); + statusBar.setMonitorID(monitor.ID); + } + } // start its' update thread Events::setThread(); @@ -128,7 +206,7 @@ void CWindowManager::cleanupUnusedWorkspaces() { workspaces.clear(); for (auto& work : temp) { - if (work.getID() != activeWorkspace->getID()) { + if (!isWorkspaceVisible(work.getID())) { // check if it has any children bool hasChildren = false; for (auto& window : windows) { @@ -156,11 +234,12 @@ void CWindowManager::refreshDirtyWindows() { setEffectiveSizePosUsingConfig(&window); // Fullscreen flag - bool bHasFullscreenWindow = activeWorkspace->getHasFullscreenWindow(); + bool bHasFullscreenWindow = getWorkspaceByID(window.getWorkspaceID())->getHasFullscreenWindow(); - // first and foremost, let's check if the window isn't on a different workspace + // first and foremost, let's check if the window isn't on a hidden workspace // or that it is not a non-fullscreen window in a fullscreen workspace - if ((window.getWorkspaceID() != activeWorkspace->getID()) || (bHasFullscreenWindow && !window.getFullscreen())) { + if (!isWorkspaceVisible(window.getWorkspaceID()) + || (bHasFullscreenWindow && !window.getFullscreen())) { // 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 =) @@ -310,8 +389,10 @@ CWindow* CWindowManager::findWindowAtCursor() { free(pointerreply); + const auto WORKSPACE = activeWorkspaces[getMonitorFromCursor()->ID]; + for (auto& window : windows) { - if (window.getWorkspaceID() == activeWorkspace->getID() && !window.getIsFloating()) { + if (window.getWorkspaceID() == WORKSPACE->getID() && !window.getIsFloating()) { if (cursorPos.x >= window.getPosition().x && cursorPos.x <= window.getPosition().x + window.getSize().x @@ -322,6 +403,8 @@ CWindow* CWindowManager::findWindowAtCursor() { } } } + + return nullptr; } void CWindowManager::calculateNewTileSetOldTile(CWindow* pWindow) { @@ -349,8 +432,9 @@ void CWindowManager::calculateNewTileSetOldTile(CWindow* pWindow) { PLASTWINDOW->setDirty(true); } else { // Open a fullscreen window - pWindow->setSize(Vector2D(Screen->width_in_pixels, Screen->height_in_pixels)); - pWindow->setPosition(Vector2D(0, 0)); + const auto MONITOR = getMonitorFromCursor(); + pWindow->setSize(Vector2D(MONITOR->vecSize.x, MONITOR->vecSize.y)); + pWindow->setPosition(Vector2D(MONITOR->vecPosition.x, MONITOR->vecPosition.y)); } } @@ -378,7 +462,7 @@ void CWindowManager::calculateNewWindowParams(CWindow* pWindow) { bool CWindowManager::isNeighbor(CWindow* a, CWindow* b) { - if (a->getWorkspaceID() != b->getWorkspaceID()) + if (a->getWorkspaceID() != b->getWorkspaceID() || getMonitorFromWindow(a) != getMonitorFromWindow(b)) return false; // Different workspaces const auto POSA = a->getPosition(); @@ -431,7 +515,8 @@ bool CWindowManager::canEatWindow(CWindow* a, CWindow* toEat) { }; for (auto& w : windows) { - if (w.getDrawable() == a->getDrawable() || w.getDrawable() == toEat->getDrawable() || w.getWorkspaceID() != toEat->getWorkspaceID() || w.getIsFloating()) + if (w.getDrawable() == a->getDrawable() || w.getDrawable() == toEat->getDrawable() || w.getWorkspaceID() != toEat->getWorkspaceID() + || w.getIsFloating() || getMonitorFromWindow(&w) != getMonitorFromWindow(toEat)) continue; if (doOverlap(&w)) @@ -457,14 +542,16 @@ void CWindowManager::fixWindowOnClose(CWindow* pClosedWindow) { if (!pClosedWindow) return; + const auto WORKSPACE = activeWorkspaces[getMonitorFromWindow(pClosedWindow)->ID]; + // Fix if was fullscreen if (pClosedWindow->getFullscreen()) - activeWorkspace->setHasFullscreenWindow(false); + WORKSPACE->setHasFullscreenWindow(false); // get the first neighboring window CWindow* neighbor = nullptr; for(auto& w : windows) { - if (w.getDrawable() == pClosedWindow->getDrawable()) + if (w.getDrawable() == pClosedWindow->getDrawable() || getMonitorFromWindow(&w) != getMonitorFromWindow(pClosedWindow)) continue; if (isNeighbor(&w, pClosedWindow) && canEatWindow(&w, pClosedWindow)) { @@ -568,19 +655,29 @@ void CWindowManager::moveActiveWindowTo(char dir) { } void CWindowManager::changeWorkspaceByID(int ID) { + + const auto MONITOR = getMonitorFromCursor(); + for (auto& workspace : workspaces) { if (workspace.getID() == ID) { - activeWorkspace = &workspace; - LastWindow = -1; - return; + if (workspace.getMonitor() == MONITOR->ID) { + activeWorkspaces[MONITOR->ID] = &workspace; + LastWindow = -1; + return; + } else { + activeWorkspaces[workspace.getMonitor()] = &workspace; + LastWindow = -1; + return; + } } } // If we are here it means the workspace is new. Let's create it. CWorkspace newWorkspace; newWorkspace.setID(ID); + newWorkspace.setMonitor(MONITOR->ID); workspaces.push_back(newWorkspace); - activeWorkspace = &workspaces[workspaces.size() - 1]; + activeWorkspaces[MONITOR->ID] = &workspaces[workspaces.size() - 1]; LastWindow = -1; } @@ -627,4 +724,39 @@ CWorkspace* CWindowManager::getWorkspaceByID(int ID) { } return nullptr; -} \ No newline at end of file +} + +SMonitor* CWindowManager::getMonitorFromWindow(CWindow* pWindow) { + return &monitors[pWindow->getMonitor()]; +} + +SMonitor* CWindowManager::getMonitorFromCursor() { + const auto POINTERCOOKIE = xcb_query_pointer(DisplayConnection, Screen->root); + + xcb_query_pointer_reply_t* pointerreply = xcb_query_pointer_reply(DisplayConnection, POINTERCOOKIE, NULL); + if (!pointerreply) { + Debug::log(ERR, "Couldn't query pointer."); + return nullptr; + } + + const auto CURSORPOS = Vector2D(pointerreply->root_x, pointerreply->root_y); + free(pointerreply); + + for (auto& monitor : monitors) { + if (VECINRECT(CURSORPOS, monitor.vecPosition.x, monitor.vecPosition.y, monitor.vecPosition.x + monitor.vecSize.x, monitor.vecPosition.y + monitor.vecSize.y)) + return &monitor; + } + + // should never happen tho, I'm using >= and the cursor cant get outside the screens, i hope. + return nullptr; +} + +bool CWindowManager::isWorkspaceVisible(int workspaceID) { + + for (auto& workspace : activeWorkspaces) { + if (workspace->getID() == workspaceID) + return true; + } + + return false; +} diff --git a/src/windowManager.hpp b/src/windowManager.hpp index cdb009a..54d7f4c 100644 --- a/src/windowManager.hpp +++ b/src/windowManager.hpp @@ -11,6 +11,7 @@ #include "utilities/Workspace.hpp" #include "bar/Bar.hpp" #include "config/ConfigManager.hpp" +#include "utilities/Monitor.hpp" class CWindowManager { public: @@ -19,6 +20,8 @@ public: xcb_drawable_t Drawable; uint32_t Values[3]; + std::vector monitors; + bool modKeyDown = false; uint8_t Depth = 32; @@ -28,7 +31,7 @@ public: xcb_drawable_t LastWindow = -1; std::vector workspaces; - CWorkspace* activeWorkspace = nullptr; + std::vector activeWorkspaces; CStatusBar statusBar; std::thread* barThread; @@ -56,10 +59,15 @@ public: void setAllWindowsDirty(); -private: + SMonitor* getMonitorFromWindow(CWindow*); + SMonitor* getMonitorFromCursor(); + + private: // Internal WM functions that don't have to be exposed + void setupRandrMonitors(); + CWindow* getNeighborInDir(char dir); void eatWindow(CWindow* a, CWindow* toEat); bool canEatWindow(CWindow* a, CWindow* toEat); @@ -70,6 +78,7 @@ private: void setEffectiveSizePosUsingConfig(CWindow* pWindow); void cleanupUnusedWorkspaces(); xcb_visualtype_t* setupColors(); + bool isWorkspaceVisible(int workspaceID); };