diff --git a/README.md b/README.md index bec0e909..e734e190 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ Nevertheless, REPORT any you find! Make an issue! - Easily expandable and readable codebase - Support for docks/whatever - Monitor rules - - Tiling/floating windows + - Socket-based IPC + - Tiling/floating/fullscreen windows - Moving/resizing windows # Major to-dos diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 8ee3f3fe..4fe3b91f 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -379,6 +379,15 @@ CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) { return nullptr; } +CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { + for (auto& w : m_lWindows) { + if (w.m_iWorkspaceID == ID && w.m_bIsFullscreen) + return &w; + } + + return nullptr; +} + bool CCompositor::isWorkspaceVisible(const int& w) { for (auto& m : m_lMonitors) { if (m.activeWorkspace == w) @@ -426,13 +435,15 @@ CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) { void CCompositor::fixXWaylandWindowsOnWorkspace(const int& id) { const auto ISVISIBLE = isWorkspaceVisible(id); + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); + for (auto& w : m_lWindows) { 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) + if (ISVISIBLE && (!PWORKSPACE->hasFullscreenWindow || w.m_bIsFullscreen)) g_pXWaylandManager->moveXWaylandWindow(&w, w.m_vRealPosition); else g_pXWaylandManager->moveXWaylandWindow(&w, Vector2D(42069,42069)); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 0b520f22..580e1ec4 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -86,6 +86,7 @@ public: int getWindowsOnWorkspace(const int&); CWindow* getFirstWindowOnWorkspace(const int&); void fixXWaylandWindowsOnWorkspace(const int&); + CWindow* getFullscreenWindowOnWorkspace(const int&); private: void initAllSignals(); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index e97e2456..3777e28d 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -50,6 +50,13 @@ void Events::listener_unmapWindow(wl_listener* listener, void* data) { if (g_pXWaylandManager->getWindowSurface(PWINDOW) == g_pCompositor->m_pLastFocus) g_pCompositor->m_pLastFocus = nullptr; + + // remove the fullscreen window status from workspace if we closed it + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); + + if (PWORKSPACE->hasFullscreenWindow && PWINDOW->m_bIsFullscreen) + PWORKSPACE->hasFullscreenWindow = false; + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); g_pCompositor->removeWindowFromVectorSafe(PWINDOW); @@ -87,9 +94,7 @@ void Events::listener_setTitleWindow(wl_listener* listener, void* data) { void Events::listener_fullscreenWindow(wl_listener* listener, void* data) { CWindow* PWINDOW = wl_container_of(listener, PWINDOW, listen_fullscreenWindow); - PWINDOW->m_bIsFullscreen = !PWINDOW->m_bIsFullscreen; - - // todo: do it + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW); Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen); } diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index e496fbd9..5d598c24 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -228,6 +228,12 @@ void CHyprDwindleLayout::onWindowRemoved(CWindow* pWindow) { void CHyprDwindleLayout::recalculateMonitor(const int& monid) { const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); + + // Ignore any recalc events if we have a fullscreen window. + if (PWORKSPACE->hasFullscreenWindow) + return; + const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace); if (TOPNODE && PMONITOR) { @@ -238,6 +244,15 @@ 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) { @@ -248,8 +263,16 @@ void CHyprDwindleLayout::changeWindowFloatingMode(CWindow* pWindow) { } void CHyprDwindleLayout::onBeginDragWindow() { + const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; + m_vBeginDragSizeXY = Vector2D(); + + if (DRAGGINGWINDOW->m_bIsFullscreen) { + Debug::log(LOG, "Rejecting drag on a fullscreen window."); + return; + } + // 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!"); @@ -264,7 +287,8 @@ void CHyprDwindleLayout::onBeginDragWindow() { void CHyprDwindleLayout::onMouseMove(const Vector2D& mousePos) { const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; - if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) + // Window invalid or drag begin size 0,0 meaning we rejected it. + if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) return; const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); @@ -317,4 +341,60 @@ void CHyprDwindleLayout::onWindowCreatedFloating(CWindow* pWindow) { pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y); } } +} + +void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow) { + if (!g_pCompositor->windowValidMapped(pWindow)) + return; + + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); + + if (PWORKSPACE->hasFullscreenWindow && !pWindow->m_bIsFullscreen) { + // if the window wants to be fullscreen but there already is one, + // ignore the request. + return; + } + + // otherwise, accept it. + pWindow->m_bIsFullscreen = !pWindow->m_bIsFullscreen; + PWORKSPACE->hasFullscreenWindow = !PWORKSPACE->hasFullscreenWindow; + + if (!pWindow->m_bIsFullscreen) { + // if it got its fullscreen disabled, set back its node if it had one + const auto PNODE = getNodeFromWindow(pWindow); + if (PNODE) + applyNodeDataToWindow(PNODE); + else { + // get back its' dimensions from position and size + pWindow->m_vEffectivePosition = pWindow->m_vPosition; + pWindow->m_vEffectiveSize = pWindow->m_vSize; + + // TEMP: Remove when anims added + pWindow->m_vRealPosition = pWindow->m_vEffectivePosition; + pWindow->m_vRealSize = pWindow->m_vEffectiveSize; + g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize); + } + } else { + // if it now got fullscreen, make it fullscreen + + // save position and size if floating + if (pWindow->m_bIsFloating) { + pWindow->m_vPosition = pWindow->m_vRealPosition; + pWindow->m_vSize = pWindow->m_vRealSize; + } + + // apply new pos and size being monitors' box + pWindow->m_vEffectivePosition = PMONITOR->vecPosition; + pWindow->m_vEffectiveSize = PMONITOR->vecSize; + + // TEMP: Remove when anims added + pWindow->m_vRealPosition = pWindow->m_vEffectivePosition; + pWindow->m_vRealSize = pWindow->m_vEffectiveSize; + g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize); + } + + // we need to fix XWayland windows by sending them to NARNIA + // because otherwise they'd still be recieving mouse events + g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace); } \ No newline at end of file diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 7474f484..61b76be7 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -36,6 +36,7 @@ public: virtual void onBeginDragWindow(); virtual void onMouseMove(const Vector2D&); virtual void onWindowCreatedFloating(CWindow*); + virtual void fullscreenRequestForWindow(CWindow*); private: diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index c3fbd667..e437d703 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -6,14 +6,48 @@ interface IHyprLayout { public: + /* + Called when a window is created (mapped) + */ virtual void onWindowCreated(CWindow*) = 0; + /* + Called when a window is removed (unmapped) + */ virtual void onWindowRemoved(CWindow*) = 0; + /* + Called when a the monitor requires a layout recalculation + this usually means reserved area changes + */ virtual void recalculateMonitor(const int&) = 0; - // Floating windows + /* + Called when a window is requested to be floated + */ virtual void changeWindowFloatingMode(CWindow*) = 0; + /* + 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; + /* + 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; + /* + Called when a window requests to toggle its' fullscreen state. + The layout sets all the fullscreen flags. + It can either accept or ignore. + */ + virtual void fullscreenRequestForWindow(CWindow*) = 0; + }; \ No newline at end of file diff --git a/src/managers/InputManager.cpp b/src/managers/InputManager.cpp index 530e1fd9..af1a3856 100644 --- a/src/managers/InputManager.cpp +++ b/src/managers/InputManager.cpp @@ -20,15 +20,30 @@ void CInputManager::onMouseWarp(wlr_event_pointer_motion_absolute* e) { void CInputManager::mouseMoveUnified(uint32_t time) { - // first top layers wlr_surface* foundSurface = nullptr; Vector2D mouseCoords = getMouseCoordsInternal(); const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); Vector2D surfacePos; - foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfacePos); + // first, we check if the workspace doesnt have a fullscreen window + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); + if (PWORKSPACE->hasFullscreenWindow) { + const auto PFULLSCREENWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->ID); + + // should never ever happen but who knows + if (PFULLSCREENWINDOW) { + foundSurface = g_pXWaylandManager->getWindowSurface(PFULLSCREENWINDOW); + if (foundSurface) + surfacePos = PFULLSCREENWINDOW->m_vRealPosition; + } + } + + // then surfaces on top if (!foundSurface) - foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfacePos); + foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfacePos); + + if (!foundSurface) + foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfacePos); // then windows if (!foundSurface && g_pCompositor->vectorToWindowIdeal(mouseCoords)) { @@ -79,6 +94,8 @@ void CInputManager::onMouseButton(wlr_event_pointer_button* e) { dragButton = e->button; g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); + + return; } break; case WLR_BUTTON_RELEASED: @@ -87,8 +104,6 @@ void CInputManager::onMouseButton(wlr_event_pointer_button* e) { break; } - g_pCompositor->focusWindow(g_pCompositor->vectorToWindowIdeal(Vector2D(g_pCompositor->m_sWLRCursor->x, g_pCompositor->m_sWLRCursor->y))); - // notify app if we didnt handle it wlr_seat_pointer_notify_button(g_pCompositor->m_sWLRSeat, e->time_msec, e->button, e->state); } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index befff4b8..a26a943b 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -44,6 +44,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t else if (k.handler == "killactive") { killActive(k.arg); } else if (k.handler == "togglefloating") { toggleActiveFloating(k.arg); } else if (k.handler == "workspace") { changeworkspace(k.arg); } + else if (k.handler == "fullscreen") { fullscreenActive(k.arg); } found = true; } @@ -143,4 +144,13 @@ void CKeybindManager::changeworkspace(std::string args) { // we need to move XWayland windows to narnia or otherwise they will still process our cursor and shit // and that'd be annoying as hell g_pCompositor->fixXWaylandWindowsOnWorkspace(OLDWORKSPACE); +} + +void CKeybindManager::fullscreenActive(std::string args) { + const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus); + + if (!g_pCompositor->windowValidMapped(PWINDOW)) + return; + + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW); } \ No newline at end of file diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index abff6b4b..817b34fb 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -27,6 +27,7 @@ private: void spawn(std::string); void toggleActiveFloating(std::string); void changeworkspace(std::string); + void fullscreenActive(std::string); }; inline std::unique_ptr g_pKeybindManager; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 0424931a..6239c3c5 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -55,6 +55,35 @@ bool shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) { return false; } +void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, SWorkspace* pWorkspace, timespec* time) { + for (auto& w : g_pCompositor->m_lWindows) { + if (w.m_iWorkspaceID != pWorkspace->ID || !w.m_bIsFullscreen) + continue; + + // found it! + renderWindow(&w, pMonitor, time, false); + } +} + +void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* time, bool decorate) { + // border + if (decorate) + drawBorderForWindow(pWindow, pMonitor); + + SRenderData renderdata = {pMonitor->output, time, pWindow->m_vRealPosition.x, pWindow->m_vRealPosition.y}; + + wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata); + + if (pWindow->m_bIsX11) { + if (pWindow->m_uSurface.xwayland->surface) { + wlr_surface_for_each_surface(pWindow->m_uSurface.xwayland->surface, renderSurface, &renderdata); + } + } + else { + wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata); + } +} + void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { const auto PMONITOR = g_pCompositor->getMonitorFromID(ID); @@ -71,30 +100,16 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { wlr_surface_for_each_surface(ls->layerSurface->surface, renderSurface, &renderdata); } - for (auto& w : g_pCompositor->m_lWindows) { + // if there is a fullscreen window, render it and then do not render anymore. + // fullscreen window will hide other windows and top layers + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); - if (w.m_bIsX11) - continue; - - if (!shouldRenderWindow(&w, PMONITOR)) - continue; - - // render the bad boy - - // border - drawBorderForWindow(&w, PMONITOR); - - SRenderData renderdata = {PMONITOR->output, time, w.m_vRealPosition.x, w.m_vRealPosition.y}; - - wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(&w), renderSurface, &renderdata); - wlr_xdg_surface_for_each_popup_surface(w.m_uSurface.xdg, renderSurface, &renderdata); + if (PWORKSPACE->hasFullscreenWindow) { + renderWorkspaceWithFullscreenWindow(PMONITOR, PWORKSPACE, time); + return; } for (auto& w : g_pCompositor->m_lWindows) { - - if (!w.m_bIsX11) - continue; - if (!g_pCompositor->windowValidMapped(&w)) continue; @@ -102,14 +117,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { continue; // render the bad boy - - // border - drawBorderForWindow(&w, PMONITOR); - - SRenderData renderdata = {PMONITOR->output, time, w.m_vRealPosition.x, w.m_vRealPosition.y}; - - if (w.m_uSurface.xwayland->surface) - wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(&w), renderSurface, &renderdata); + renderWindow(&w, PMONITOR, time, true); } // Render surfaces above windows for monitor diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index a2781693..2d7d8eb9 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -3,6 +3,7 @@ #include "../defines.hpp" #include #include "../helpers/Monitor.hpp" +#include "../helpers/Workspace.hpp" #include "../Window.hpp" class CHyprRenderer { @@ -16,6 +17,8 @@ public: private: void arrangeLayerArray(SMonitor*, const std::list&, bool, wlr_box*); void drawBorderForWindow(CWindow*, SMonitor*); + void renderWorkspaceWithFullscreenWindow(SMonitor*, SWorkspace*, timespec*); + void renderWindow(CWindow*, SMonitor*, timespec*, bool); }; inline std::unique_ptr g_pHyprRenderer;