mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-05-19 08:30:22 -07:00
1032 lines
46 KiB
C++
1032 lines
46 KiB
C++
#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 "managers/AnimationManager.hpp"
|
|
#include "managers/PointerManager.hpp"
|
|
#include "../desktop/LayerSurface.hpp"
|
|
#include "../managers/LayoutManager.hpp"
|
|
#include "../managers/EventManager.hpp"
|
|
#include "../managers/AnimationManager.hpp"
|
|
|
|
#include <hyprutils/string/String.hpp>
|
|
using namespace Hyprutils::String;
|
|
using namespace Hyprutils::Animation;
|
|
|
|
// ------------------------------------------------------------ //
|
|
// __ _______ _ _ _____ ______ _______ //
|
|
// \ \ / /_ _| \ | | __ \ / __ \ \ / / ____| //
|
|
// \ \ /\ / / | | | \| | | | | | | \ \ /\ / / (___ //
|
|
// \ \/ \/ / | | | . ` | | | | | | |\ \/ \/ / \___ \ //
|
|
// \ /\ / _| |_| |\ | |__| | |__| | \ /\ / ____) | //
|
|
// \/ \/ |_____|_| \_|_____/ \____/ \/ \/ |_____/ //
|
|
// //
|
|
// ------------------------------------------------------------ //
|
|
|
|
static void setVector2DAnimToMove(WP<CBaseAnimatedVariable> pav) {
|
|
const auto PAV = pav.lock();
|
|
if (!PAV)
|
|
return;
|
|
|
|
CAnimatedVariable<Vector2D>* animvar = dynamic_cast<CAnimatedVariable<Vector2D>*>(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 = ((CWindow*)owner)->m_self.lock();
|
|
|
|
static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity");
|
|
static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity");
|
|
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
|
|
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
|
|
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("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<SInitialWorkspaceToken>(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
|
|
PWINDOW->m_matchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
|
|
std::optional<eFullscreenMode> requestedInternalFSMode, requestedClientFSMode;
|
|
std::optional<SFullscreenState> requestedFSState;
|
|
if (PWINDOW->m_wantsInitialFullscreen || (PWINDOW->m_isX11 && PWINDOW->m_xwaylandSurface->m_fullscreen))
|
|
requestedClientFSMode = FSMODE_FULLSCREEN;
|
|
MONITORID requestedFSMonitor = PWINDOW->m_wantsInitialFullscreenMonitor;
|
|
|
|
for (auto const& r : PWINDOW->m_matchedRules) {
|
|
switch (r->m_ruleType) {
|
|
case CWindowRule::RULE_MONITOR: {
|
|
try {
|
|
const auto MONITORSTR = trim(r->m_rule.substr(r->m_rule.find(' ')));
|
|
|
|
if (MONITORSTR == "unset") {
|
|
PWINDOW->m_monitor = PMONITOR;
|
|
} else {
|
|
if (isNumber(MONITORSTR)) {
|
|
const MONITORID MONITOR = std::stoi(MONITORSTR);
|
|
if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM)
|
|
PWINDOW->m_monitor = PM;
|
|
else
|
|
PWINDOW->m_monitor = g_pCompositor->m_monitors.at(0);
|
|
} else {
|
|
const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
|
|
if (PMONITOR)
|
|
PWINDOW->m_monitor = PMONITOR;
|
|
else {
|
|
Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->m_rule, r->m_value, e.what()); }
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_WORKSPACE: {
|
|
// check if it isnt unset
|
|
const auto WORKSPACERQ = r->m_rule.substr(r->m_rule.find_first_of(' ') + 1);
|
|
|
|
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, r->m_value);
|
|
requestedFSMonitor = MONITOR_INVALID;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_FLOAT: {
|
|
PWINDOW->m_isFloating = true;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_TILE: {
|
|
PWINDOW->m_isFloating = false;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_PSEUDO: {
|
|
PWINDOW->m_isPseudotiled = true;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_NOINITIALFOCUS: {
|
|
PWINDOW->m_noInitialFocus = true;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_FULLSCREENSTATE: {
|
|
const auto ARGS = CVarList(r->m_rule.substr(r->m_rule.find_first_of(' ') + 1), 2, ' ');
|
|
int internalMode, clientMode;
|
|
try {
|
|
internalMode = std::stoi(ARGS[0]);
|
|
} catch (std::exception& e) { internalMode = 0; }
|
|
try {
|
|
clientMode = std::stoi(ARGS[1]);
|
|
} catch (std::exception& e) { clientMode = 0; }
|
|
requestedFSState = SFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_SUPPRESSEVENT: {
|
|
CVarList vars(r->m_rule, 0, 's', true);
|
|
for (size_t i = 1; i < vars.size(); ++i) {
|
|
if (vars[i] == "fullscreen")
|
|
PWINDOW->m_suppressedEvents |= SUPPRESS_FULLSCREEN;
|
|
else if (vars[i] == "maximize")
|
|
PWINDOW->m_suppressedEvents |= SUPPRESS_MAXIMIZE;
|
|
else if (vars[i] == "activate")
|
|
PWINDOW->m_suppressedEvents |= SUPPRESS_ACTIVATE;
|
|
else if (vars[i] == "activatefocus")
|
|
PWINDOW->m_suppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
|
|
else if (vars[i] == "fullscreenoutput")
|
|
PWINDOW->m_suppressedEvents |= SUPPRESS_FULLSCREEN_OUTPUT;
|
|
else
|
|
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
|
|
}
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_PIN: {
|
|
PWINDOW->m_pinned = true;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_FULLSCREEN: {
|
|
requestedInternalFSMode = FSMODE_FULLSCREEN;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_MAXIMIZE: {
|
|
requestedInternalFSMode = FSMODE_MAXIMIZED;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_STAYFOCUSED: {
|
|
PWINDOW->m_stayFocused = true;
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_GROUP: {
|
|
if (PWINDOW->m_groupRules & GROUP_OVERRIDE)
|
|
continue;
|
|
|
|
// `group` is a shorthand of `group set`
|
|
if (trim(r->m_rule) == "group") {
|
|
PWINDOW->m_groupRules |= GROUP_SET;
|
|
continue;
|
|
}
|
|
|
|
CVarList vars(r->m_rule, 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;
|
|
}
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_CONTENT: {
|
|
const CVarList VARS(r->m_rule, 0, ' ');
|
|
try {
|
|
PWINDOW->setContentType(NContentType::fromString(VARS[1]));
|
|
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->m_rule, e.what()); }
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_NOCLOSEFOR: {
|
|
const CVarList VARS(r->m_rule, 0, ' ');
|
|
try {
|
|
PWINDOW->m_closeableSince = Time::steadyNow() + std::chrono::milliseconds(std::stoull(VARS[1]));
|
|
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->m_rule, e.what()); }
|
|
}
|
|
default: break;
|
|
}
|
|
|
|
PWINDOW->applyDynamicRule(r);
|
|
}
|
|
|
|
// 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;
|
|
|
|
CVarList WORKSPACEARGS = CVarList(requestedWorkspace, 0, ' ');
|
|
|
|
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, requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_name, PWINDOW->m_class, PWINDOW->m_title)});
|
|
|
|
if (PWINDOW->m_isFloating) {
|
|
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
|
|
PWINDOW->m_createdOverFullscreen = true;
|
|
|
|
// size and move rules
|
|
for (auto const& r : PWINDOW->m_matchedRules) {
|
|
switch (r->m_ruleType) {
|
|
case CWindowRule::RULE_SIZE: {
|
|
try {
|
|
auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) {
|
|
if (VALUE.starts_with('<'))
|
|
return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
|
|
else if (VALUE.starts_with('>'))
|
|
return std::max(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
|
|
|
|
return stringToPercentage(VALUE, REL);
|
|
};
|
|
|
|
const auto VALUE = r->m_rule.substr(r->m_rule.find(' ') + 1);
|
|
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
|
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
|
|
|
|
const auto MAXSIZE = PWINDOW->requestedMaxSize();
|
|
|
|
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->m_size.x) :
|
|
stringToFloatClamp(SIZEXSTR, PWINDOW->m_realSize->goal().x, PMONITOR->m_size.x);
|
|
|
|
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->m_size.y) :
|
|
stringToFloatClamp(SIZEYSTR, PWINDOW->m_realSize->goal().y, PMONITOR->m_size.y);
|
|
|
|
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
|
|
|
|
PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY});
|
|
|
|
PWINDOW->setHidden(false);
|
|
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->m_rule, r->m_value); }
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_MOVE: {
|
|
try {
|
|
auto value = r->m_rule.substr(r->m_rule.find(' ') + 1);
|
|
|
|
const bool ONSCREEN = value.starts_with("onscreen");
|
|
|
|
if (ONSCREEN)
|
|
value = value.substr(value.find_first_of(' ') + 1);
|
|
|
|
const bool CURSOR = value.starts_with("cursor");
|
|
|
|
if (CURSOR)
|
|
value = value.substr(value.find_first_of(' ') + 1);
|
|
|
|
const auto POSXSTR = value.substr(0, value.find(' '));
|
|
const auto POSYSTR = value.substr(value.find(' ') + 1);
|
|
|
|
int posX = 0;
|
|
int posY = 0;
|
|
|
|
if (POSXSTR.starts_with("100%-")) {
|
|
const bool subtractWindow = POSXSTR.starts_with("100%-w-");
|
|
const auto POSXRAW = (subtractWindow) ? POSXSTR.substr(7) : POSXSTR.substr(5);
|
|
posX =
|
|
PMONITOR->m_size.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->m_size.x);
|
|
|
|
if (subtractWindow)
|
|
posX -= PWINDOW->m_realSize->goal().x;
|
|
|
|
if (CURSOR)
|
|
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
|
|
} else if (!CURSOR) {
|
|
posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->m_size.x;
|
|
} else {
|
|
// cursor
|
|
if (POSXSTR == "cursor") {
|
|
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->m_position.x;
|
|
} else {
|
|
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->m_position.x +
|
|
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_realSize->goal().x);
|
|
}
|
|
}
|
|
|
|
if (POSYSTR.starts_with("100%-")) {
|
|
const bool subtractWindow = POSYSTR.starts_with("100%-w-");
|
|
const auto POSYRAW = (subtractWindow) ? POSYSTR.substr(7) : POSYSTR.substr(5);
|
|
posY =
|
|
PMONITOR->m_size.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->m_size.y);
|
|
|
|
if (subtractWindow)
|
|
posY -= PWINDOW->m_realSize->goal().y;
|
|
|
|
if (CURSOR)
|
|
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
|
|
} else if (!CURSOR) {
|
|
posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->m_size.y;
|
|
} else {
|
|
// cursor
|
|
if (POSYSTR == "cursor") {
|
|
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->m_position.y;
|
|
} else {
|
|
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->m_position.y +
|
|
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_realSize->goal().y);
|
|
}
|
|
}
|
|
|
|
if (ONSCREEN) {
|
|
int borderSize = PWINDOW->getRealBorderSize();
|
|
|
|
posX = std::clamp(posX, (int)(PMONITOR->m_reservedTopLeft.x + borderSize),
|
|
(int)(PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x - PWINDOW->m_realSize->goal().x - borderSize));
|
|
|
|
posY = std::clamp(posY, (int)(PMONITOR->m_reservedTopLeft.y + borderSize),
|
|
(int)(PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y - PWINDOW->m_realSize->goal().y - borderSize));
|
|
}
|
|
|
|
Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
|
|
|
|
*PWINDOW->m_realPosition = Vector2D(posX, posY) + PMONITOR->m_position;
|
|
|
|
PWINDOW->setHidden(false);
|
|
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r->m_rule, r->m_value); }
|
|
break;
|
|
}
|
|
case CWindowRule::RULE_CENTER: {
|
|
auto RESERVEDOFFSET = Vector2D();
|
|
const auto ARGS = CVarList(r->m_rule, 2, ' ');
|
|
if (ARGS[1] == "1")
|
|
RESERVEDOFFSET = (PMONITOR->m_reservedTopLeft - PMONITOR->m_reservedBottomRight) / 2.f;
|
|
|
|
*PWINDOW->m_realPosition = PMONITOR->middle() - PWINDOW->m_realSize->goal() / 2.f + RESERVEDOFFSET;
|
|
break;
|
|
}
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
|
|
for (auto const& r : PWINDOW->m_matchedRules) {
|
|
if (r->m_ruleType != CWindowRule::RULE_SIZE)
|
|
continue;
|
|
|
|
try {
|
|
const auto VALUE = r->m_rule.substr(r->m_rule.find(' ') + 1);
|
|
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
|
|
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
|
|
|
|
const auto MAXSIZE = PWINDOW->requestedMaxSize();
|
|
|
|
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->m_size.x) : stringToPercentage(SIZEXSTR, PMONITOR->m_size.x);
|
|
|
|
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->m_size.y) : stringToPercentage(SIZEYSTR, PMONITOR->m_size.y);
|
|
|
|
Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW);
|
|
|
|
setPseudo = true;
|
|
PWINDOW->m_pseudoSize = Vector2D(SIZEX, SIZEY);
|
|
|
|
PWINDOW->setHidden(false);
|
|
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->m_rule, r->m_value); }
|
|
}
|
|
|
|
if (!setPseudo)
|
|
PWINDOW->m_pseudoSize = PWINDOW->m_realSize->goal() - Vector2D(10, 10);
|
|
}
|
|
|
|
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_lastWindow.lock();
|
|
|
|
if (PWINDOW->m_windowData.allowsInput.valueOrDefault()) { // if default value wasn't set to false getPriority() would throw an exception
|
|
PWINDOW->m_windowData.noFocus = CWindowOverridableVar(false, PWINDOW->m_windowData.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_windowData.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_windowData.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 = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_FULLSCREEN);
|
|
if (requestedClientFSMode.has_value() && (PWINDOW->m_suppressedEvents & SUPPRESS_MAXIMIZE))
|
|
requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)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_windowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE);
|
|
g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value());
|
|
} else if (requestedInternalFSMode.has_value() && requestedClientFSMode.has_value() && !PWINDOW->m_windowData.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();
|
|
|
|
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_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
|
|
PWINDOW->m_alpha->setValueAndWarp(0.f);
|
|
*PWINDOW->m_alpha = 1.f;
|
|
|
|
PWINDOW->m_realPosition->setCallbackOnEnd(setVector2DAnimToMove);
|
|
PWINDOW->m_realSize->setCallbackOnEnd(setVector2DAnimToMove);
|
|
|
|
// recalc the values for this window
|
|
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
|
|
// 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 = ((CWindow*)owner)->m_self.lock();
|
|
|
|
Debug::log(LOG, "{:c} unmapped", PWINDOW);
|
|
|
|
static auto PEXITRETAINSFS = CConfigValue<Hyprlang::INT>("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 &&
|
|
std::any_of(PWINDOW->m_matchedRules.begin(), PWINDOW->m_matchedRules.end(), [](const auto& r) { return r->m_ruleType == CWindowRule::RULE_PERSISTENTSIZE; })) {
|
|
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->makeWindowSnapshot(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<Hyprlang::INT>("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 onWindowPostCreateClose will ignore it
|
|
|
|
// anims
|
|
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
|
|
*PWINDOW->m_alpha = 0.f;
|
|
|
|
// 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 = ((CWindow*)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;
|
|
|
|
PWINDOW->m_reportedSize = PWINDOW->m_pendingReportedSize; // apply pending size. We pinged, the window ponged.
|
|
|
|
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<Vector2D>{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 = ((CWindow*)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 = ((CWindow*)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 = ((CWindow*)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<Hyprlang::INT>("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();
|
|
}
|
|
}
|