compositor: Configurable behavior when window to be focused conflicts with fullscreen (#12033)

Renames `misc:new_window_takes_over_fullscreen` into
`misc:on_focus_under_fullscreen` and implements the following behavior:

- By default, when a tiling window is being focused on a workspace where
  a fullscreen/maximized window exists, respect
  the `misc:on_focus_under_fullscreen` config variable.
This commit is contained in:
Nikolai Nechaev 2025-11-26 07:44:26 +09:00 committed by GitHub
parent 1c1746de61
commit 40d8fa8491
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 1003 additions and 694 deletions

View file

@ -7,6 +7,7 @@
#include <bit>
#include <string_view>
#include "Window.hpp"
#include "state/FocusState.hpp"
#include "../Compositor.hpp"
#include "../render/decorations/CHyprDropShadowDecoration.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
@ -121,9 +122,9 @@ CWindow::CWindow(SP<CXWaylandSurface> surface) : m_xwaylandSurface(surface) {
}
CWindow::~CWindow() {
if (g_pCompositor->m_lastWindow == m_self) {
g_pCompositor->m_lastFocus.reset();
g_pCompositor->m_lastWindow.reset();
if (Desktop::focusState()->window() == m_self) {
Desktop::focusState()->surface().reset();
Desktop::focusState()->window().reset();
}
m_events.destroy.emit();
@ -528,8 +529,6 @@ void CWindow::onUnmap() {
if (m_workspace->m_isSpecialWorkspace && m_workspace->getWindows() == 0)
m_lastWorkspace = m_monitor->activeWorkspaceID();
std::erase_if(g_pCompositor->m_windowFocusHistory, [this](const auto& other) { return other.expired() || other == m_self; });
if (*PCLOSEONLASTSPECIAL && m_workspace && m_workspace->getWindows() == 0 && onSpecialWorkspace()) {
const auto PMONITOR = m_monitor.lock();
if (PMONITOR && PMONITOR->m_activeSpecialWorkspace && PMONITOR->m_activeSpecialWorkspace == m_workspace)
@ -594,8 +593,6 @@ void CWindow::onMap() {
m_movingFromWorkspaceAlpha->setValueAndWarp(1.F);
g_pCompositor->m_windowFocusHistory.push_back(m_self);
m_reportedSize = m_pendingReportedSize;
m_animatingIn = true;
@ -629,8 +626,8 @@ void CWindow::onBorderAngleAnimEnd(WP<CBaseAnimatedVariable> pav) {
void CWindow::setHidden(bool hidden) {
m_hidden = hidden;
if (hidden && g_pCompositor->m_lastWindow == m_self)
g_pCompositor->m_lastWindow.reset();
if (hidden && Desktop::focusState()->window() == m_self)
Desktop::focusState()->window().reset();
setSuspended(hidden);
}
@ -862,7 +859,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
const auto WORKSPACE = PCURRENT->m_workspace;
const auto MODE = PCURRENT->m_fullscreenState.internal;
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_lastWindow.lock();
const auto CURRENTISFOCUS = PCURRENT == Desktop::focusState()->window();
const auto PWINDOWSIZE = PCURRENT->m_realSize->value();
const auto PWINDOWPOS = PCURRENT->m_realPosition->value();
@ -897,7 +894,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (CURRENTISFOCUS)
g_pCompositor->focusWindow(pWindow);
Desktop::focusState()->rawWindowFocus(pWindow);
g_pHyprRenderer->damageWindow(pWindow);
@ -1240,7 +1237,7 @@ std::unordered_map<std::string, std::string> CWindow::getEnv() {
}
void CWindow::activate(bool force) {
if (g_pCompositor->m_lastWindow == m_self)
if (Desktop::focusState()->window() == m_self)
return;
static auto PFOCUSONACTIVATE = CConfigValue<Hyprlang::INT>("misc:focus_on_activate");
@ -1262,7 +1259,7 @@ void CWindow::activate(bool force) {
if (m_isFloating)
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
g_pCompositor->focusWindow(m_self.lock());
Desktop::focusState()->fullWindowFocus(m_self.lock());
warpCursor();
}
@ -1276,7 +1273,7 @@ void CWindow::onUpdateState() {
if (m_isMapped) {
const auto monitor = g_pCompositor->getMonitorFromID(requestsID.value());
g_pCompositor->moveWindowToWorkspaceSafe(m_self.lock(), monitor->m_activeWorkspace);
g_pCompositor->setActiveMonitor(monitor);
Desktop::focusState()->rawMonitorFocus(monitor);
}
if (!m_isMapped)
@ -1311,7 +1308,7 @@ void CWindow::onUpdateMeta() {
g_pEventManager->postEvent(SHyprIPCEvent{.event = "windowtitlev2", .data = std::format("{:x},{}", rc<uintptr_t>(this), m_title)});
EMIT_HOOK_EVENT("windowTitle", m_self.lock());
if (m_self == g_pCompositor->m_lastWindow) { // if it's the active, let's post an event to update others
if (m_self == Desktop::focusState()->window()) { // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = m_class + "," + m_title});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", rc<uintptr_t>(this))});
EMIT_HOOK_EVENT("activeWindow", m_self.lock());
@ -1325,7 +1322,7 @@ void CWindow::onUpdateMeta() {
if (m_class != NEWCLASS) {
m_class = NEWCLASS;
if (m_self == g_pCompositor->m_lastWindow) { // if it's the active, let's post an event to update others
if (m_self == Desktop::focusState()->window()) { // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = m_class + "," + m_title});
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", rc<uintptr_t>(this))});
EMIT_HOOK_EVENT("activeWindow", m_self.lock());
@ -1502,7 +1499,7 @@ PHLWINDOW CWindow::getSwallower() {
return candidates[0];
// walk up the focus history and find the last focused
for (auto const& w : g_pCompositor->m_windowFocusHistory) {
for (auto const& w : Desktop::focusState()->windowHistory()) {
if (!w)
continue;
@ -1781,7 +1778,7 @@ void CWindow::updateDecorationValues() {
setBorderColor(*RENDERDATA.borderGradient);
else {
const bool GROUPLOCKED = m_groupData.pNextWindow.lock() ? getGroupHead()->m_groupData.locked : false;
if (m_self == g_pCompositor->m_lastWindow) {
if (m_self == Desktop::focusState()->window()) {
const auto* const ACTIVECOLOR =
!m_groupData.pNextWindow.lock() ? (!m_groupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
setBorderColor(m_ruleApplicator->activeBorderColor().valueOr(*ACTIVECOLOR));
@ -1797,7 +1794,7 @@ void CWindow::updateDecorationValues() {
if (isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) {
*m_activeInactiveAlpha = m_ruleApplicator->alphaFullscreen().valueOrDefault().applyAlpha(*PFULLSCREENALPHA);
} else {
if (m_self == g_pCompositor->m_lastWindow)
if (m_self == Desktop::focusState()->window())
*m_activeInactiveAlpha = m_ruleApplicator->alpha().valueOrDefault().applyAlpha(*PACTIVEALPHA);
else
*m_activeInactiveAlpha = m_ruleApplicator->alphaInactive().valueOrDefault().applyAlpha(*PINACTIVEALPHA);
@ -1805,7 +1802,7 @@ void CWindow::updateDecorationValues() {
// dim
float goalDim = 1.F;
if (m_self == g_pCompositor->m_lastWindow.lock() || m_ruleApplicator->noDim().valueOrDefault() || !*PDIMENABLED)
if (m_self == Desktop::focusState()->window() || m_ruleApplicator->noDim().valueOrDefault() || !*PDIMENABLED)
goalDim = 0;
else
goalDim = *PDIMSTRENGTH;
@ -1817,7 +1814,7 @@ void CWindow::updateDecorationValues() {
// shadow
if (!isX11OverrideRedirect() && !m_X11DoesntWantBorders) {
if (m_self == g_pCompositor->m_lastWindow)
if (m_self == Desktop::focusState()->window())
*m_realShadowColor = CHyprColor(*PSHADOWCOL);
else
*m_realShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != -1 ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
@ -1828,7 +1825,7 @@ void CWindow::updateDecorationValues() {
}
std::optional<double> CWindow::calculateSingleExpr(const std::string& s) {
const auto PMONITOR = m_monitor ? m_monitor : g_pCompositor->m_lastMonitor;
const auto PMONITOR = m_monitor ? m_monitor : Desktop::focusState()->monitor();
const auto CURSOR_LOCAL = g_pInputManager->getMouseCoordsInternal() - (PMONITOR ? PMONITOR->m_position : Vector2D{});
Math::CExpression expr;