#include "Events.hpp" #include "../Compositor.hpp" #include "../helpers/WLClasses.hpp" #include "../helpers/AsyncDialogBox.hpp" #include "../managers/input/InputManager.hpp" #include "../managers/TokenManager.hpp" #include "../managers/SeatManager.hpp" #include "../render/Renderer.hpp" #include "../config/ConfigValue.hpp" #include "../config/ConfigManager.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" #include "../protocols/types/ContentType.hpp" #include "../xwayland/XSurface.hpp" #include "desktop/DesktopTypes.hpp" #include "managers/animation/AnimationManager.hpp" #include "managers/animation/DesktopAnimationManager.hpp" #include "managers/PointerManager.hpp" #include "../desktop/LayerSurface.hpp" #include "../managers/LayoutManager.hpp" #include "../managers/EventManager.hpp" #include "../managers/animation/AnimationManager.hpp" #include using namespace Hyprutils::String; using namespace Hyprutils::Animation; // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // // \ \ / /_ _| \ | | __ \ / __ \ \ / / ____| // // \ \ /\ / / | | | \| | | | | | | \ \ /\ / / (___ // // \ \/ \/ / | | | . ` | | | | | | |\ \/ \/ / \___ \ // // \ /\ / _| |_| |\ | |__| | |__| | \ /\ / ____) | // // \/ \/ |_____|_| \_|_____/ \____/ \/ \/ |_____/ // // // // ------------------------------------------------------------ // static void setVector2DAnimToMove(WP pav) { const auto PAV = pav.lock(); if (!PAV) return; CAnimatedVariable* animvar = dc*>(PAV.get()); animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove")); const auto PHLWINDOW = animvar->m_Context.pWindow.lock(); if (PHLWINDOW) PHLWINDOW->m_animatingIn = false; } void Events::listener_mapWindow(void* owner, void* data) { PHLWINDOW PWINDOW = sc(owner)->m_self.lock(); static auto PINACTIVEALPHA = CConfigValue("decoration:inactive_opacity"); static auto PACTIVEALPHA = CConfigValue("decoration:active_opacity"); static auto PDIMSTRENGTH = CConfigValue("decoration:dim_strength"); static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); auto PMONITOR = g_pCompositor->m_lastMonitor.lock(); if (!g_pCompositor->m_lastMonitor) { g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({})); PMONITOR = g_pCompositor->m_lastMonitor.lock(); } auto PWORKSPACE = PMONITOR->m_activeSpecialWorkspace ? PMONITOR->m_activeSpecialWorkspace : PMONITOR->m_activeWorkspace; PWINDOW->m_monitor = PMONITOR; PWINDOW->m_workspace = PWORKSPACE; PWINDOW->m_isMapped = true; PWINDOW->m_readyToDelete = false; PWINDOW->m_fadingOut = false; PWINDOW->m_title = PWINDOW->fetchTitle(); PWINDOW->m_firstMap = true; PWINDOW->m_initialTitle = PWINDOW->m_title; PWINDOW->m_initialClass = PWINDOW->fetchClass(); // check for token std::string requestedWorkspace = ""; bool workspaceSilent = false; if (*PINITIALWSTRACKING) { const auto WINDOWENV = PWINDOW->getEnv(); if (WINDOWENV.contains("HL_INITIAL_WORKSPACE_TOKEN")) { const auto SZTOKEN = WINDOWENV.at("HL_INITIAL_WORKSPACE_TOKEN"); Debug::log(LOG, "New window contains HL_INITIAL_WORKSPACE_TOKEN: {}", SZTOKEN); const auto TOKEN = g_pTokenManager->getToken(SZTOKEN); if (TOKEN) { // find workspace and use it SInitialWorkspaceToken WS = std::any_cast(TOKEN->m_data); Debug::log(LOG, "HL_INITIAL_WORKSPACE_TOKEN {} -> {}", SZTOKEN, WS.workspace); if (g_pCompositor->getWorkspaceByString(WS.workspace) != PWINDOW->m_workspace) { requestedWorkspace = WS.workspace; workspaceSilent = true; } if (*PINITIALWSTRACKING == 1) // one-shot token g_pTokenManager->removeToken(TOKEN); else if (*PINITIALWSTRACKING == 2) { // persistent if (WS.primaryOwner.expired()) { WS.primaryOwner = PWINDOW; TOKEN->m_data = WS; } PWINDOW->m_initialWorkspaceToken = SZTOKEN; } } } } if (g_pInputManager->m_lastFocusOnLS) // waybar fix g_pInputManager->releaseAllMouseButtons(); // checks if the window wants borders and sets the appropriate flag g_pXWaylandManager->checkBorders(PWINDOW); // registers the animated vars and stuff PWINDOW->onMap(); const auto PWINDOWSURFACE = PWINDOW->m_wlSurface->resource(); if (!PWINDOWSURFACE) { g_pCompositor->removeWindowFromVectorSafe(PWINDOW); return; } if (g_pXWaylandManager->shouldBeFloated(PWINDOW)) { PWINDOW->m_isFloating = true; PWINDOW->m_requestsFloat = true; } PWINDOW->m_X11ShouldntFocus = PWINDOW->m_X11ShouldntFocus || (PWINDOW->m_isX11 && PWINDOW->isX11OverrideRedirect() && !PWINDOW->m_xwaylandSurface->wantsFocus()); // window rules std::optional requestedInternalFSMode, requestedClientFSMode; std::optional requestedFSState; if (PWINDOW->m_wantsInitialFullscreen || (PWINDOW->m_isX11 && PWINDOW->m_xwaylandSurface->m_fullscreen)) requestedClientFSMode = FSMODE_FULLSCREEN; MONITORID requestedFSMonitor = PWINDOW->m_wantsInitialFullscreenMonitor; PWINDOW->m_ruleApplicator->readStaticRules(); { if (!PWINDOW->m_ruleApplicator->static_.monitor.empty()) { const auto& MONITORSTR = PWINDOW->m_ruleApplicator->static_.monitor; if (MONITORSTR == "unset") PWINDOW->m_monitor = PMONITOR; else { const auto MONITOR = g_pCompositor->getMonitorFromString(MONITORSTR); if (MONITOR) { PWINDOW->m_monitor = MONITOR; const auto PMONITORFROMID = PWINDOW->m_monitor.lock(); if (PWINDOW->m_monitor != PMONITOR) { g_pKeybindManager->m_dispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID())); PMONITOR = PMONITORFROMID; } PWINDOW->m_workspace = PMONITOR->m_activeSpecialWorkspace ? PMONITOR->m_activeSpecialWorkspace : PMONITOR->m_activeWorkspace; PWORKSPACE = PWINDOW->m_workspace; Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW); requestedFSMonitor = MONITOR_INVALID; } else Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR); } } if (!PWINDOW->m_ruleApplicator->static_.workspace.empty()) { const auto WORKSPACERQ = PWINDOW->m_ruleApplicator->static_.workspace; if (WORKSPACERQ == "unset") requestedWorkspace = ""; else requestedWorkspace = WORKSPACERQ; const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ; if (JUSTWORKSPACE == PWORKSPACE->m_name || JUSTWORKSPACE == "name:" + PWORKSPACE->m_name) requestedWorkspace = ""; Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, PWINDOW->m_ruleApplicator->static_.workspace); requestedFSMonitor = MONITOR_INVALID; } if (PWINDOW->m_ruleApplicator->static_.floating.has_value()) PWINDOW->m_isFloating = PWINDOW->m_ruleApplicator->static_.floating.value(); if (PWINDOW->m_ruleApplicator->static_.pseudo) PWINDOW->m_isPseudotiled = true; if (PWINDOW->m_ruleApplicator->static_.noInitialFocus) PWINDOW->m_noInitialFocus = true; if (PWINDOW->m_ruleApplicator->static_.fullscreenStateClient || PWINDOW->m_ruleApplicator->static_.fullscreenStateInternal) { requestedFSState = SFullscreenState{ .internal = sc(PWINDOW->m_ruleApplicator->static_.fullscreenStateInternal.value_or(0)), .client = sc(PWINDOW->m_ruleApplicator->static_.fullscreenStateClient.value_or(0)), }; } if (!PWINDOW->m_ruleApplicator->static_.suppressEvent.empty()) { for (const auto& var : PWINDOW->m_ruleApplicator->static_.suppressEvent) { if (var == "fullscreen") PWINDOW->m_suppressedEvents |= SUPPRESS_FULLSCREEN; else if (var == "maximize") PWINDOW->m_suppressedEvents |= SUPPRESS_MAXIMIZE; else if (var == "activate") PWINDOW->m_suppressedEvents |= SUPPRESS_ACTIVATE; else if (var == "activatefocus") PWINDOW->m_suppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY; else if (var == "fullscreenoutput") PWINDOW->m_suppressedEvents |= SUPPRESS_FULLSCREEN_OUTPUT; else Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", var); } } if (PWINDOW->m_ruleApplicator->static_.pin) PWINDOW->m_pinned = true; if (PWINDOW->m_ruleApplicator->static_.fullscreen) requestedInternalFSMode = FSMODE_FULLSCREEN; if (PWINDOW->m_ruleApplicator->static_.maximize) requestedInternalFSMode = FSMODE_MAXIMIZED; if (!PWINDOW->m_ruleApplicator->static_.group.empty()) { if (!(PWINDOW->m_groupRules & GROUP_OVERRIDE) && trim(PWINDOW->m_ruleApplicator->static_.group) != "group") { CVarList2 vars(std::string{PWINDOW->m_ruleApplicator->static_.group}, 0, 's'); std::string vPrev = ""; for (auto const& v : vars) { if (v == "group") continue; if (v == "set") { PWINDOW->m_groupRules |= GROUP_SET; } else if (v == "new") { // shorthand for `group barred set` PWINDOW->m_groupRules |= (GROUP_SET | GROUP_BARRED); } else if (v == "lock") { PWINDOW->m_groupRules |= GROUP_LOCK; } else if (v == "invade") { PWINDOW->m_groupRules |= GROUP_INVADE; } else if (v == "barred") { PWINDOW->m_groupRules |= GROUP_BARRED; } else if (v == "deny") { PWINDOW->m_groupData.deny = true; } else if (v == "override") { // Clear existing rules PWINDOW->m_groupRules = GROUP_OVERRIDE; } else if (v == "unset") { // Clear existing rules and stop processing PWINDOW->m_groupRules = GROUP_OVERRIDE; break; } else if (v == "always") { if (vPrev == "set" || vPrev == "group") PWINDOW->m_groupRules |= GROUP_SET_ALWAYS; else if (vPrev == "lock") PWINDOW->m_groupRules |= GROUP_LOCK_ALWAYS; else Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev); } vPrev = v; } } } if (PWINDOW->m_ruleApplicator->static_.content) PWINDOW->setContentType(sc(PWINDOW->m_ruleApplicator->static_.content.value())); if (PWINDOW->m_ruleApplicator->static_.noCloseFor) PWINDOW->m_closeableSince = Time::steadyNow() + std::chrono::milliseconds(PWINDOW->m_ruleApplicator->static_.noCloseFor.value()); } // make it uncloseable if it's a Hyprland dialog // TODO: make some closeable? if (CAsyncDialogBox::isAsyncDialogBox(PWINDOW->getPID())) PWINDOW->m_closeableSince = Time::steadyNow() + std::chrono::years(10 /* Should be enough, no? */); // disallow tiled pinned if (PWINDOW->m_pinned && !PWINDOW->m_isFloating) PWINDOW->m_pinned = false; CVarList2 WORKSPACEARGS = CVarList2(std::move(requestedWorkspace), 0, ' ', false, false); if (!WORKSPACEARGS[0].empty()) { WORKSPACEID requestedWorkspaceID; std::string requestedWorkspaceName; if (WORKSPACEARGS.contains("silent")) workspaceSilent = true; if (WORKSPACEARGS.contains("empty") && PWORKSPACE->getWindows() <= 1) { requestedWorkspaceID = PWORKSPACE->m_id; requestedWorkspaceName = PWORKSPACE->m_name; } else { auto result = getWorkspaceIDNameFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0)); requestedWorkspaceID = result.id; requestedWorkspaceName = result.name; } if (requestedWorkspaceID != WORKSPACE_INVALID) { auto pWorkspace = g_pCompositor->getWorkspaceByID(requestedWorkspaceID); if (!pWorkspace) pWorkspace = g_pCompositor->createNewWorkspace(requestedWorkspaceID, PWINDOW->monitorID(), requestedWorkspaceName, false); PWORKSPACE = pWorkspace; PWINDOW->m_workspace = pWorkspace; PWINDOW->m_monitor = pWorkspace->m_monitor; if (PWINDOW->m_monitor.lock()->m_activeSpecialWorkspace && !pWorkspace->m_isSpecialWorkspace) workspaceSilent = true; if (!workspaceSilent) { if (pWorkspace->m_isSpecialWorkspace) pWorkspace->m_monitor->setSpecialWorkspace(pWorkspace); else if (PMONITOR->activeWorkspaceID() != requestedWorkspaceID && !PWINDOW->m_noInitialFocus) g_pKeybindManager->m_dispatchers["workspace"](requestedWorkspaceName); PMONITOR = g_pCompositor->m_lastMonitor.lock(); } requestedFSMonitor = MONITOR_INVALID; } else workspaceSilent = false; } if (PWINDOW->m_suppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT) requestedFSMonitor = MONITOR_INVALID; else if (requestedFSMonitor != MONITOR_INVALID) { if (const auto PM = g_pCompositor->getMonitorFromID(requestedFSMonitor); PM) PWINDOW->m_monitor = PM; const auto PMONITORFROMID = PWINDOW->m_monitor.lock(); if (PWINDOW->m_monitor != PMONITOR) { g_pKeybindManager->m_dispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID())); PMONITOR = PMONITORFROMID; } PWINDOW->m_workspace = PMONITOR->m_activeSpecialWorkspace ? PMONITOR->m_activeSpecialWorkspace : PMONITOR->m_activeWorkspace; PWORKSPACE = PWINDOW->m_workspace; Debug::log(LOG, "Requested monitor, applying to {:mw}", PWINDOW); } if (PWORKSPACE->m_defaultFloating) PWINDOW->m_isFloating = true; if (PWORKSPACE->m_defaultPseudo) { PWINDOW->m_isPseudotiled = true; CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(PWINDOW); PWINDOW->m_pseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height); } PWINDOW->updateWindowData(); // Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped. const auto SWALLOWER = PWINDOW->getSwallower(); PWINDOW->m_swallowed = SWALLOWER; if (PWINDOW->m_swallowed) PWINDOW->m_swallowed->m_currentlySwallowed = true; // emit the IPC event before the layout might focus the window to avoid a focus event first g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, PWORKSPACE->m_name, PWINDOW->m_class, PWINDOW->m_title)}); if (PWINDOW->m_isFloating) { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); PWINDOW->m_createdOverFullscreen = true; if (!PWINDOW->m_ruleApplicator->static_.size.empty()) { const auto COMPUTED = PWINDOW->calculateExpression(PWINDOW->m_ruleApplicator->static_.size); if (!COMPUTED) Debug::log(ERR, "failed to parse {} as an expression", PWINDOW->m_ruleApplicator->static_.size); else { *PWINDOW->m_realSize = *COMPUTED; PWINDOW->setHidden(false); } } if (!PWINDOW->m_ruleApplicator->static_.position.empty()) { const auto COMPUTED = PWINDOW->calculateExpression(PWINDOW->m_ruleApplicator->static_.position); if (!COMPUTED) Debug::log(ERR, "failed to parse {} as an expression", PWINDOW->m_ruleApplicator->static_.position); else { *PWINDOW->m_realPosition = *COMPUTED + PMONITOR->m_position; PWINDOW->setHidden(false); } } if (PWINDOW->m_ruleApplicator->static_.center) { auto RESERVEDOFFSET = (PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight) / 2.f; *PWINDOW->m_realPosition = PMONITOR->middle() - PWINDOW->m_realSize->goal() / 2.f + RESERVEDOFFSET; } // set the pseudo size to the GOAL of our current size // because the windows are animated on RealSize PWINDOW->m_pseudoSize = PWINDOW->m_realSize->goal(); g_pCompositor->changeWindowZOrder(PWINDOW, true); } else { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); bool setPseudo = false; if (!PWINDOW->m_ruleApplicator->static_.size.empty()) { const auto COMPUTED = PWINDOW->calculateExpression(PWINDOW->m_ruleApplicator->static_.size); if (!COMPUTED) Debug::log(ERR, "failed to parse {} as an expression", PWINDOW->m_ruleApplicator->static_.size); else { setPseudo = true; PWINDOW->m_pseudoSize = *COMPUTED; PWINDOW->setHidden(false); } } if (!setPseudo) PWINDOW->m_pseudoSize = PWINDOW->m_realSize->goal() - Vector2D(10, 10); } const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_lastWindow.lock(); if (PWINDOW->m_ruleApplicator->allowsInput().valueOrDefault()) { // if default value wasn't set to false getPriority() would throw an exception PWINDOW->m_ruleApplicator->noFocusOverride(Desktop::Types::COverridableVar(false, PWINDOW->m_ruleApplicator->allowsInput().getPriority())); PWINDOW->m_noInitialFocus = false; PWINDOW->m_X11ShouldntFocus = false; } // check LS focus grab const auto PFORCEFOCUS = g_pCompositor->getForceFocus(); const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_lastFocus.lock()); if (PLSFROMFOCUS && PLSFROMFOCUS->m_layerSurface->m_current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) PWINDOW->m_noInitialFocus = true; if (PWINDOW->m_workspace->m_hasFullscreenWindow && !requestedInternalFSMode.has_value() && !requestedClientFSMode.has_value() && !PWINDOW->m_isFloating) { if (*PNEWTAKESOVERFS == 0) PWINDOW->m_noInitialFocus = true; else if (*PNEWTAKESOVERFS == 1) requestedInternalFSMode = PWINDOW->m_workspace->m_fullscreenMode; else if (*PNEWTAKESOVERFS == 2) g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_workspace->getFullscreenWindow(), FSMODE_NONE); } if (!PWINDOW->m_ruleApplicator->noFocus().valueOrDefault() && !PWINDOW->m_noInitialFocus && (!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_isX11 && PWINDOW->m_xwaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->m_activeInactiveAlpha->setValueAndWarp(*PACTIVEALPHA); PWINDOW->m_dimPercent->setValueAndWarp(PWINDOW->m_ruleApplicator->noDim().valueOrDefault() ? 0.f : *PDIMSTRENGTH); } else { PWINDOW->m_activeInactiveAlpha->setValueAndWarp(*PINACTIVEALPHA); PWINDOW->m_dimPercent->setValueAndWarp(0); } if (requestedClientFSMode.has_value() && (PWINDOW->m_suppressedEvents & SUPPRESS_FULLSCREEN)) requestedClientFSMode = sc(sc(requestedClientFSMode.value_or(FSMODE_NONE)) & ~sc(FSMODE_FULLSCREEN)); if (requestedClientFSMode.has_value() && (PWINDOW->m_suppressedEvents & SUPPRESS_MAXIMIZE)) requestedClientFSMode = sc(sc(requestedClientFSMode.value_or(FSMODE_NONE)) & ~sc(FSMODE_MAXIMIZED)); if (!PWINDOW->m_noInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) { // fix fullscreen on requested (basically do a switcheroo) if (PWINDOW->m_workspace->m_hasFullscreenWindow) g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_workspace->getFullscreenWindow(), FSMODE_NONE); PWINDOW->m_realPosition->warp(); PWINDOW->m_realSize->warp(); if (requestedFSState.has_value()) { PWINDOW->m_ruleApplicator->syncFullscreenOverride(Desktop::Types::COverridableVar(false, Desktop::Types::PRIORITY_WINDOW_RULE)); g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value()); } else if (requestedInternalFSMode.has_value() && requestedClientFSMode.has_value() && !PWINDOW->m_ruleApplicator->syncFullscreen().valueOrDefault()) g_pCompositor->setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = requestedInternalFSMode.value(), .client = requestedClientFSMode.value()}); else if (requestedInternalFSMode.has_value()) g_pCompositor->setWindowFullscreenInternal(PWINDOW, requestedInternalFSMode.value()); else if (requestedClientFSMode.has_value()) g_pCompositor->setWindowFullscreenClient(PWINDOW, requestedClientFSMode.value()); } // recheck idle inhibitors g_pInputManager->recheckIdleInhibitorStatus(); PWINDOW->updateToplevel(); PWINDOW->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_ALL); if (workspaceSilent) { if (validMapped(PFOCUSEDWINDOWPREV)) { g_pCompositor->focusWindow(PFOCUSEDWINDOWPREV); PFOCUSEDWINDOWPREV->updateWindowDecos(); // need to for some reason i cba to find out why } else if (!PFOCUSEDWINDOWPREV) g_pCompositor->focusWindow(nullptr); } // swallow if (SWALLOWER) { g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER); g_pHyprRenderer->damageWindow(SWALLOWER); SWALLOWER->setHidden(true); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID()); } PWINDOW->m_firstMap = false; Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->m_name, PWINDOW->m_realPosition->goal(), PWINDOW->m_realSize->goal()); // emit the hook event here after basic stuff has been initialized EMIT_HOOK_EVENT("openWindow", PWINDOW); // apply data from default decos. Borders, shadows. g_pDecorationPositioner->forceRecalcFor(PWINDOW); PWINDOW->updateWindowDecos(); g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW); // do animations g_pDesktopAnimationManager->startAnimation(PWINDOW, CDesktopAnimationManager::ANIMATION_TYPE_IN); PWINDOW->m_realPosition->setCallbackOnEnd(setVector2DAnimToMove); PWINDOW->m_realSize->setCallbackOnEnd(setVector2DAnimToMove); // recalc the values for this window PWINDOW->updateDecorationValues(); // avoid this window being visible if (PWORKSPACE->m_hasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_isFloating) PWINDOW->m_alpha->setValueAndWarp(0.f); g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_wlSurface->resource(), PMONITOR->m_scale); g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_wlSurface->resource(), PMONITOR->m_transform); if (g_pSeatManager->m_mouse.expired() || !g_pInputManager->isConstrained()) g_pInputManager->sendMotionEventsToFocused(); // fix some xwayland apps that don't behave nicely PWINDOW->m_reportedSize = PWINDOW->m_pendingReportedSize; if (PWINDOW->m_workspace) PWINDOW->m_workspace->updateWindows(); if (PMONITOR && PWINDOW->isX11OverrideRedirect()) PWINDOW->m_X11SurfaceScaledBy = PMONITOR->m_scale; } void Events::listener_unmapWindow(void* owner, void* data) { PHLWINDOW PWINDOW = sc(owner)->m_self.lock(); Debug::log(LOG, "{:c} unmapped", PWINDOW); static auto PEXITRETAINSFS = CConfigValue("misc:exit_window_retains_fullscreen"); const auto CURRENTWINDOWFSSTATE = PWINDOW->isFullscreen(); const auto CURRENTFSMODE = PWINDOW->m_fullscreenState.internal; if (!PWINDOW->m_wlSurface->exists() || !PWINDOW->m_isMapped) { Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW); PWINDOW->m_fadingOut = false; return; } const auto PMONITOR = PWINDOW->m_monitor.lock(); if (PMONITOR) { PWINDOW->m_originalClosedPos = PWINDOW->m_realPosition->value() - PMONITOR->m_position; PWINDOW->m_originalClosedSize = PWINDOW->m_realSize->value(); PWINDOW->m_originalClosedExtents = PWINDOW->getFullWindowExtents(); } g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)}); EMIT_HOOK_EVENT("closeWindow", PWINDOW); if (PWINDOW->m_isFloating && !PWINDOW->m_isX11 && PWINDOW->m_ruleApplicator->persistentSize().valueOrDefault()) { Debug::log(LOG, "storing floating size {}x{} for window {}::{} on close", PWINDOW->m_realSize->value().x, PWINDOW->m_realSize->value().y, PWINDOW->m_class, PWINDOW->m_title); g_pConfigManager->storeFloatingSize(PWINDOW, PWINDOW->m_realSize->value()); } PROTO::toplevelExport->onWindowUnmap(PWINDOW); if (PWINDOW->isFullscreen()) g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); // Allow the renderer to catch the last frame. if (g_pHyprRenderer->shouldRenderWindow(PWINDOW)) g_pHyprRenderer->makeSnapshot(PWINDOW); // swallowing if (valid(PWINDOW->m_swallowed)) { if (PWINDOW->m_swallowed->m_currentlySwallowed) { PWINDOW->m_swallowed->m_currentlySwallowed = false; PWINDOW->m_swallowed->setHidden(false); if (PWINDOW->m_groupData.pNextWindow.lock()) PWINDOW->m_swallowed->m_groupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false. g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_swallowed.lock()); } PWINDOW->m_swallowed->m_groupSwallowed = false; PWINDOW->m_swallowed.reset(); } bool wasLastWindow = false; if (PWINDOW == g_pCompositor->m_lastWindow.lock()) { wasLastWindow = true; g_pCompositor->m_lastWindow.reset(); g_pCompositor->m_lastFocus.reset(); g_pInputManager->releaseAllMouseButtons(); } if (PWINDOW == g_pInputManager->m_currentlyDraggedWindow.lock()) g_pKeybindManager->changeMouseBindMode(MBIND_INVALID); // remove the fullscreen window status from workspace if we closed it const auto PWORKSPACE = PWINDOW->m_workspace; if (PWORKSPACE->m_hasFullscreenWindow && PWINDOW->isFullscreen()) PWORKSPACE->m_hasFullscreenWindow = false; g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW); // do this after onWindowRemoved because otherwise it'll think the window is invalid PWINDOW->m_isMapped = false; // refocus on a new window if needed if (wasLastWindow) { static auto FOCUSONCLOSE = CConfigValue("input:focus_on_close"); PHLWINDOW PWINDOWCANDIDATE = nullptr; if (*FOCUSONCLOSE) PWINDOWCANDIDATE = (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING)); else PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW); Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE); if (PWINDOWCANDIDATE != g_pCompositor->m_lastWindow.lock() && PWINDOWCANDIDATE) { g_pCompositor->focusWindow(PWINDOWCANDIDATE); if (*PEXITRETAINSFS && CURRENTWINDOWFSSTATE) g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE); } if (!PWINDOWCANDIDATE && PWINDOW->m_workspace && PWINDOW->m_workspace->getWindows() == 0) g_pInputManager->refocus(); g_pInputManager->sendMotionEventsToFocused(); // CWindow::onUnmap will remove this window's active status, but we can't really do it above. if (PWINDOW == g_pCompositor->m_lastWindow.lock() || !g_pCompositor->m_lastWindow.lock()) { g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""}); EMIT_HOOK_EVENT("activeWindow", PHLWINDOW{nullptr}); } } else { Debug::log(LOG, "Unmapped was not focused, ignoring a refocus."); } PWINDOW->m_fadingOut = true; g_pCompositor->addToFadingOutSafe(PWINDOW); if (!PWINDOW->m_X11DoesntWantBorders) // don't animate out if they weren't animated in. *PWINDOW->m_realPosition = PWINDOW->m_realPosition->value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise CesktopAnimationManager will ignore it // anims g_pDesktopAnimationManager->startAnimation(PWINDOW, CDesktopAnimationManager::ANIMATION_TYPE_OUT); // recheck idle inhibitors g_pInputManager->recheckIdleInhibitorStatus(); // force report all sizes (QT sometimes has an issue with this) if (PWINDOW->m_workspace) PWINDOW->m_workspace->forceReportSizesToWindows(); // update lastwindow after focus PWINDOW->onUnmap(); } void Events::listener_commitWindow(void* owner, void* data) { PHLWINDOW PWINDOW = sc(owner)->m_self.lock(); if (!PWINDOW->m_isX11 && PWINDOW->m_xdgSurface->m_initialCommit) { Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow(PWINDOW); Debug::log(LOG, "Layout predicts size {} for {}", predSize, PWINDOW); PWINDOW->m_xdgSurface->m_toplevel->setSize(predSize); return; } if (!PWINDOW->m_isMapped || PWINDOW->isHidden()) return; if (PWINDOW->m_isX11) PWINDOW->m_reportedSize = PWINDOW->m_pendingReportedSize; if (!PWINDOW->m_isX11 && !PWINDOW->isFullscreen() && PWINDOW->m_isFloating) { const auto MINSIZE = PWINDOW->m_xdgSurface->m_toplevel->layoutMinSize(); const auto MAXSIZE = PWINDOW->m_xdgSurface->m_toplevel->layoutMaxSize(); PWINDOW->clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional{MAXSIZE} : std::nullopt); g_pHyprRenderer->damageWindow(PWINDOW); } if (!PWINDOW->m_workspace->m_visible) return; const auto PMONITOR = PWINDOW->m_monitor.lock(); if (PMONITOR) PMONITOR->debugLastPresentation(g_pSeatManager->m_isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow"); if (g_pSeatManager->m_isPointerFrameCommit) { g_pSeatManager->m_isPointerFrameSkipped = false; g_pSeatManager->m_isPointerFrameCommit = false; } else g_pHyprRenderer->damageSurface(PWINDOW->m_wlSurface->resource(), PWINDOW->m_realPosition->goal().x, PWINDOW->m_realPosition->goal().y, PWINDOW->m_isX11 ? 1.0 / PWINDOW->m_X11SurfaceScaledBy : 1.0); if (g_pSeatManager->m_isPointerFrameSkipped) { g_pPointerManager->sendStoredMovement(); g_pSeatManager->sendPointerFrame(); g_pSeatManager->m_isPointerFrameCommit = true; } if (!PWINDOW->m_isX11) { PWINDOW->m_subsurfaceHead->recheckDamageForSubsurfaces(); PWINDOW->m_popupHead->recheckTree(); } // tearing: if solitary, redraw it. This still might be a single surface window if (PMONITOR && PMONITOR->m_solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->m_tearingState.canTear && PWINDOW->m_wlSurface->resource()->m_current.texture) { CRegion damageBox{PWINDOW->m_wlSurface->resource()->m_current.accumulateBufferDamage()}; if (!damageBox.empty()) { if (PMONITOR->m_tearingState.busy) { PMONITOR->m_tearingState.frameScheduledWhileBusy = true; } else { PMONITOR->m_tearingState.nextRenderTorn = true; g_pHyprRenderer->renderMonitor(PMONITOR); } } } } void Events::listener_destroyWindow(void* owner, void* data) { PHLWINDOW PWINDOW = sc(owner)->m_self.lock(); Debug::log(LOG, "{:c} destroyed, queueing.", PWINDOW); if (PWINDOW == g_pCompositor->m_lastWindow.lock()) { g_pCompositor->m_lastWindow.reset(); g_pCompositor->m_lastFocus.reset(); } PWINDOW->m_wlSurface->unassign(); PWINDOW->m_listeners = {}; g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); PWINDOW->m_readyToDelete = true; PWINDOW->m_xdgSurface.reset(); if (!PWINDOW->m_fadingOut) { Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW); g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn } PWINDOW->m_listeners.unmap.reset(); PWINDOW->m_listeners.destroy.reset(); PWINDOW->m_listeners.map.reset(); PWINDOW->m_listeners.commit.reset(); } void Events::listener_activateX11(void* owner, void* data) { PHLWINDOW PWINDOW = sc(owner)->m_self.lock(); Debug::log(LOG, "X11 Activate request for window {}", PWINDOW); if (PWINDOW->isX11OverrideRedirect()) { Debug::log(LOG, "Unmanaged X11 {} requests activate", PWINDOW); if (g_pCompositor->m_lastWindow.lock() && g_pCompositor->m_lastWindow->getPID() != PWINDOW->getPID()) return; if (!PWINDOW->m_xwaylandSurface->wantsFocus()) return; g_pCompositor->focusWindow(PWINDOW); return; } if (PWINDOW == g_pCompositor->m_lastWindow.lock() || (PWINDOW->m_suppressedEvents & SUPPRESS_ACTIVATE)) return; PWINDOW->activate(); } void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PHLWINDOW PWINDOW = sc(owner)->m_self.lock(); if (!PWINDOW->m_isMapped || !PWINDOW->m_xwaylandSurface || !PWINDOW->m_xwaylandSurface->m_overrideRedirect) return; const auto POS = PWINDOW->m_realPosition->goal(); const auto SIZ = PWINDOW->m_realSize->goal(); if (PWINDOW->m_xwaylandSurface->m_geometry.size() > Vector2D{1, 1}) PWINDOW->setHidden(false); else PWINDOW->setHidden(true); if (PWINDOW->isFullscreen() || !PWINDOW->m_isFloating) { PWINDOW->sendWindowSize(true); g_pHyprRenderer->damageWindow(PWINDOW); return; } static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(PWINDOW->m_xwaylandSurface->m_geometry.pos()); if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_xwaylandSurface->m_geometry.width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_xwaylandSurface->m_geometry.height) > 2) { Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_xwaylandSurface->m_geometry.size()); g_pHyprRenderer->damageWindow(PWINDOW); PWINDOW->m_realPosition->setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y)); if (abs(std::floor(SIZ.x) - PWINDOW->m_xwaylandSurface->m_geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_xwaylandSurface->m_geometry.h) > 2) PWINDOW->m_realSize->setValueAndWarp(PWINDOW->m_xwaylandSurface->m_geometry.size()); if (*PXWLFORCESCALEZERO) { if (const auto PMONITOR = PWINDOW->m_monitor.lock(); PMONITOR) { PWINDOW->m_realSize->setValueAndWarp(PWINDOW->m_realSize->goal() / PMONITOR->m_scale); } } PWINDOW->m_position = PWINDOW->m_realPosition->goal(); PWINDOW->m_size = PWINDOW->m_realSize->goal(); PWINDOW->m_workspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_realPosition->value() + PWINDOW->m_realSize->value() / 2.f)->m_activeWorkspace; g_pCompositor->changeWindowZOrder(PWINDOW, true); PWINDOW->updateWindowDecos(); g_pHyprRenderer->damageWindow(PWINDOW); PWINDOW->m_reportedPosition = PWINDOW->m_realPosition->goal(); PWINDOW->m_pendingReportedSize = PWINDOW->m_realSize->goal(); } }