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:
parent
1c1746de61
commit
40d8fa8491
51 changed files with 1003 additions and 694 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#include "LayerSurface.hpp"
|
||||
#include "state/FocusState.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../events/Events.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
|
|
@ -16,7 +17,7 @@
|
|||
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
|
||||
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
|
||||
|
||||
auto pMonitor = resource->m_monitor.empty() ? g_pCompositor->m_lastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->m_monitor);
|
||||
auto pMonitor = resource->m_monitor.empty() ? Desktop::focusState()->monitor() : g_pCompositor->getMonitorFromName(resource->m_monitor);
|
||||
|
||||
pLS->m_surface->assign(resource->m_surface.lock(), pLS);
|
||||
|
||||
|
|
@ -173,7 +174,7 @@ void CLayerSurface::onMap() {
|
|||
g_pSeatManager->setGrab(nullptr);
|
||||
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
g_pCompositor->focusSurface(m_surface->resource());
|
||||
Desktop::focusState()->rawSurfaceFocus(m_surface->resource());
|
||||
|
||||
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y);
|
||||
g_pSeatManager->setPointerFocus(m_surface->resource(), LOCAL);
|
||||
|
|
@ -244,11 +245,12 @@ void CLayerSurface::onUnmap() {
|
|||
|
||||
// refocus if needed
|
||||
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
|
||||
if (WASLASTFOCUS || (g_pCompositor->m_lastFocus && g_pCompositor->m_lastFocus->m_hlSurface && !g_pCompositor->m_lastFocus->m_hlSurface->keyboardFocusable())) {
|
||||
if (WASLASTFOCUS ||
|
||||
(Desktop::focusState()->surface() && Desktop::focusState()->surface()->m_hlSurface && !Desktop::focusState()->surface()->m_hlSurface->keyboardFocusable())) {
|
||||
if (!g_pInputManager->refocusLastWindow(PMONITOR))
|
||||
g_pInputManager->refocus();
|
||||
} else if (g_pCompositor->m_lastFocus && g_pCompositor->m_lastFocus != m_surface->resource())
|
||||
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_lastFocus.lock());
|
||||
} else if (Desktop::focusState()->surface() && Desktop::focusState()->surface() != m_surface->resource())
|
||||
g_pSeatManager->setKeyboardFocus(Desktop::focusState()->surface());
|
||||
|
||||
CBox geomFixed = {m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y, m_geometry.width, m_geometry.height};
|
||||
g_pHyprRenderer->damageBox(geomFixed);
|
||||
|
|
@ -374,7 +376,7 @@ void CLayerSurface::onCommit() {
|
|||
if (WASLASTFOCUS && m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) {
|
||||
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
|
||||
// so unfocus the surface here.
|
||||
g_pCompositor->focusSurface(nullptr);
|
||||
Desktop::focusState()->rawSurfaceFocus(nullptr);
|
||||
g_pInputManager->refocusLastWindow(m_monitor.lock());
|
||||
} else if (WASLASTFOCUS && WASEXCLUSIVE && m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) {
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
|
@ -382,7 +384,7 @@ void CLayerSurface::onCommit() {
|
|||
// if now exclusive and not previously
|
||||
g_pSeatManager->setGrab(nullptr);
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
g_pCompositor->focusSurface(m_surface->resource());
|
||||
Desktop::focusState()->rawSurfaceFocus(m_surface->resource());
|
||||
|
||||
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y);
|
||||
g_pSeatManager->setPointerFocus(m_surface->resource(), LOCAL);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "Subsurface.hpp"
|
||||
#include "../events/Events.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../desktop/state/FocusState.hpp"
|
||||
#include "../desktop/Window.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../protocols/core/Subcompositor.hpp"
|
||||
|
|
@ -163,7 +164,7 @@ void CSubsurface::onMap() {
|
|||
void CSubsurface::onUnmap() {
|
||||
damageLastArea();
|
||||
|
||||
if (m_wlSurface->resource() == g_pCompositor->m_lastFocus)
|
||||
if (m_wlSurface->resource() == Desktop::focusState()->surface())
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "../../../helpers/Monitor.hpp"
|
||||
#include "../../../Compositor.hpp"
|
||||
#include "../../../managers/TokenManager.hpp"
|
||||
#include "../../../desktop/state/FocusState.hpp"
|
||||
|
||||
using namespace Desktop;
|
||||
using namespace Desktop::Rule;
|
||||
|
|
@ -72,7 +73,7 @@ bool CWindowRule::matches(PHLWINDOW w, bool allowEnvLookup) {
|
|||
return false;
|
||||
break;
|
||||
case RULE_PROP_FOCUS:
|
||||
if (!engine->match(g_pCompositor->m_lastWindow == w))
|
||||
if (!engine->match(Desktop::focusState()->window() == w))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_GROUP:
|
||||
|
|
|
|||
330
src/desktop/state/FocusState.cpp
Normal file
330
src/desktop/state/FocusState.cpp
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
#include "FocusState.hpp"
|
||||
#include "../Window.hpp"
|
||||
#include "../../Compositor.hpp"
|
||||
#include "../../protocols/XDGShell.hpp"
|
||||
#include "../../render/Renderer.hpp"
|
||||
#include "../../managers/LayoutManager.hpp"
|
||||
#include "../../managers/EventManager.hpp"
|
||||
#include "../../managers/HookSystemManager.hpp"
|
||||
#include "../../xwayland/XSurface.hpp"
|
||||
#include "../../protocols/PointerConstraints.hpp"
|
||||
|
||||
using namespace Desktop;
|
||||
|
||||
SP<CFocusState> Desktop::focusState() {
|
||||
static SP<CFocusState> state = makeShared<CFocusState>();
|
||||
return state;
|
||||
}
|
||||
|
||||
Desktop::CFocusState::CFocusState() {
|
||||
m_windowOpen = g_pHookSystem->hookDynamic("openWindowEarly", [this](void* self, SCallbackInfo& info, std::any data) {
|
||||
auto window = std::any_cast<PHLWINDOW>(data);
|
||||
|
||||
addWindowToHistory(window);
|
||||
});
|
||||
|
||||
m_windowClose = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any data) {
|
||||
auto window = std::any_cast<PHLWINDOW>(data);
|
||||
|
||||
removeWindowFromHistory(window);
|
||||
});
|
||||
}
|
||||
|
||||
struct SFullscreenWorkspaceFocusResult {
|
||||
PHLWINDOW overrideFocusWindow = nullptr;
|
||||
};
|
||||
|
||||
static SFullscreenWorkspaceFocusResult onFullscreenWorkspaceFocusWindow(PHLWINDOW pWindow, bool forceFSCycle) {
|
||||
const auto FSWINDOW = pWindow->m_workspace->getFullscreenWindow();
|
||||
const auto FSMODE = pWindow->m_workspace->m_fullscreenMode;
|
||||
|
||||
if (pWindow == FSWINDOW)
|
||||
return {}; // no conflict
|
||||
|
||||
if (pWindow->m_isFloating) {
|
||||
// if the window is floating, just bring it to the top
|
||||
pWindow->m_createdOverFullscreen = true;
|
||||
g_pHyprRenderer->damageWindow(pWindow);
|
||||
return {};
|
||||
}
|
||||
|
||||
static auto PONFOCUSUNDERFS = CConfigValue<Hyprlang::INT>("misc:on_focus_under_fullscreen");
|
||||
|
||||
switch (*PONFOCUSUNDERFS) {
|
||||
case 0:
|
||||
// focus the fullscreen window instead
|
||||
return {.overrideFocusWindow = FSWINDOW};
|
||||
case 2:
|
||||
// undo fs, unless we force a cycle
|
||||
if (!forceFSCycle) {
|
||||
g_pCompositor->setWindowFullscreenInternal(FSWINDOW, FSMODE_NONE);
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case 1:
|
||||
// replace fullscreen
|
||||
g_pCompositor->setWindowFullscreenInternal(FSWINDOW, FSMODE_NONE);
|
||||
g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE);
|
||||
break;
|
||||
|
||||
default: Debug::log(ERR, "Invalid misc:on_focus_under_fullscreen mode: {}", *PONFOCUSUNDERFS); break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void CFocusState::fullWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surface, bool preserveFocusHistory, bool forceFSCycle) {
|
||||
if (pWindow) {
|
||||
if (!pWindow->m_workspace)
|
||||
return;
|
||||
|
||||
const auto CURRENT_FS_MODE = pWindow->m_workspace->m_hasFullscreenWindow ? pWindow->m_workspace->m_fullscreenMode : FSMODE_NONE;
|
||||
if (CURRENT_FS_MODE != FSMODE_NONE) {
|
||||
const auto RESULT = onFullscreenWorkspaceFocusWindow(pWindow, forceFSCycle);
|
||||
if (RESULT.overrideFocusWindow)
|
||||
pWindow = RESULT.overrideFocusWindow;
|
||||
}
|
||||
}
|
||||
|
||||
static auto PMODALPARENTBLOCKING = CConfigValue<Hyprlang::INT>("general:modal_parent_blocking");
|
||||
|
||||
if (*PMODALPARENTBLOCKING && pWindow && pWindow->m_xdgSurface && pWindow->m_xdgSurface->m_toplevel && pWindow->m_xdgSurface->m_toplevel->anyChildModal()) {
|
||||
Debug::log(LOG, "Refusing focus to window shadowed by modal dialog");
|
||||
return;
|
||||
}
|
||||
|
||||
rawWindowFocus(pWindow, surface, preserveFocusHistory);
|
||||
}
|
||||
|
||||
void CFocusState::rawWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surface, bool preserveFocusHistory) {
|
||||
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
|
||||
static auto PSPECIALFALLTHROUGH = CConfigValue<Hyprlang::INT>("input:special_fallthrough");
|
||||
|
||||
if (!pWindow || !pWindow->priorityFocus()) {
|
||||
if (g_pSessionLockManager->isSessionLocked()) {
|
||||
Debug::log(LOG, "Refusing a keyboard focus to a window because of a sessionlock");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_pInputManager->m_exclusiveLSes.empty()) {
|
||||
Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pWindow && pWindow->m_isX11 && pWindow->isX11OverrideRedirect() && !pWindow->m_xwaylandSurface->wantsFocus())
|
||||
return;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
|
||||
|
||||
if (!pWindow || !validMapped(pWindow)) {
|
||||
|
||||
if (m_focusWindow.expired() && !pWindow)
|
||||
return;
|
||||
|
||||
const auto PLASTWINDOW = m_focusWindow.lock();
|
||||
m_focusWindow.reset();
|
||||
|
||||
if (PLASTWINDOW && PLASTWINDOW->m_isMapped) {
|
||||
PLASTWINDOW->m_ruleApplicator->propertiesChanged(Rule::RULE_PROP_FOCUS);
|
||||
PLASTWINDOW->updateDecorationValues();
|
||||
|
||||
g_pXWaylandManager->activateWindow(PLASTWINDOW, false);
|
||||
}
|
||||
|
||||
g_pSeatManager->setKeyboardFocus(nullptr);
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""});
|
||||
|
||||
EMIT_HOOK_EVENT("activeWindow", PHLWINDOW{nullptr});
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(nullptr);
|
||||
|
||||
m_focusSurface.reset();
|
||||
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pWindow->m_ruleApplicator->noFocus().valueOrDefault()) {
|
||||
Debug::log(LOG, "Ignoring focus to nofocus window!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_focusWindow.lock() == pWindow && g_pSeatManager->m_state.keyboardFocus == surface && g_pSeatManager->m_state.keyboardFocus)
|
||||
return;
|
||||
|
||||
if (pWindow->m_pinned)
|
||||
pWindow->m_workspace = m_focusMonitor->m_activeWorkspace;
|
||||
|
||||
const auto PMONITOR = pWindow->m_monitor.lock();
|
||||
|
||||
if (!pWindow->m_workspace || !pWindow->m_workspace->isVisible()) {
|
||||
const auto PWORKSPACE = pWindow->m_workspace;
|
||||
// This is to fix incorrect feedback on the focus history.
|
||||
PWORKSPACE->m_lastFocusedWindow = pWindow;
|
||||
if (m_focusMonitor->m_activeWorkspace)
|
||||
PWORKSPACE->rememberPrevWorkspace(m_focusMonitor->m_activeWorkspace);
|
||||
if (PWORKSPACE->m_isSpecialWorkspace)
|
||||
m_focusMonitor->changeWorkspace(PWORKSPACE, false, true); // if special ws, open on current monitor
|
||||
else if (PMONITOR)
|
||||
PMONITOR->changeWorkspace(PWORKSPACE, false, true);
|
||||
// changeworkspace already calls focusWindow
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PLASTWINDOW = m_focusWindow.lock();
|
||||
m_focusWindow = pWindow;
|
||||
|
||||
/* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
|
||||
window focuses are "via keybinds" and which ones aren't. */
|
||||
if (PMONITOR && PMONITOR->m_activeSpecialWorkspace && PMONITOR->m_activeSpecialWorkspace != pWindow->m_workspace && !pWindow->m_pinned && !*PSPECIALFALLTHROUGH)
|
||||
PMONITOR->setSpecialWorkspace(nullptr);
|
||||
|
||||
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
|
||||
if (PLASTWINDOW && PLASTWINDOW->m_isMapped) {
|
||||
PLASTWINDOW->m_ruleApplicator->propertiesChanged(Rule::RULE_PROP_FOCUS);
|
||||
PLASTWINDOW->updateDecorationValues();
|
||||
|
||||
if (!pWindow->m_isX11 || !pWindow->isX11OverrideRedirect())
|
||||
g_pXWaylandManager->activateWindow(PLASTWINDOW, false);
|
||||
}
|
||||
|
||||
const auto PWINDOWSURFACE = surface ? surface : pWindow->m_wlSurface->resource();
|
||||
|
||||
rawSurfaceFocus(PWINDOWSURFACE, pWindow);
|
||||
|
||||
g_pXWaylandManager->activateWindow(pWindow, true); // sets the m_pLastWindow
|
||||
|
||||
pWindow->m_ruleApplicator->propertiesChanged(Rule::RULE_PROP_FOCUS);
|
||||
pWindow->onFocusAnimUpdate();
|
||||
pWindow->updateDecorationValues();
|
||||
|
||||
if (pWindow->m_isUrgent)
|
||||
pWindow->m_isUrgent = false;
|
||||
|
||||
// Send an event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = pWindow->m_class + "," + pWindow->m_title});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", rc<uintptr_t>(pWindow.get()))});
|
||||
|
||||
EMIT_HOOK_EVENT("activeWindow", pWindow);
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(pWindow);
|
||||
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
|
||||
if (!preserveFocusHistory) {
|
||||
// move to front of the window history
|
||||
moveWindowToLatestInHistory(pWindow);
|
||||
}
|
||||
|
||||
if (*PFOLLOWMOUSE == 0)
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
if (pWindow->m_groupData.pNextWindow)
|
||||
pWindow->deactivateGroupMembers();
|
||||
}
|
||||
|
||||
void CFocusState::rawSurfaceFocus(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindowOwner) {
|
||||
if (g_pSeatManager->m_state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->m_state.keyboardFocus == pWindowOwner->m_wlSurface->resource()))
|
||||
return; // Don't focus when already focused on this.
|
||||
|
||||
if (g_pSessionLockManager->isSessionLocked() && pSurface && !g_pSessionLockManager->isSurfaceSessionLock(pSurface))
|
||||
return;
|
||||
|
||||
if (g_pSeatManager->m_seatGrab && !g_pSeatManager->m_seatGrab->accepts(pSurface)) {
|
||||
Debug::log(LOG, "surface {:x} won't receive kb focus because grab rejected it", rc<uintptr_t>(pSurface.get()));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PLASTSURF = m_focusSurface.lock();
|
||||
|
||||
// Unfocus last surface if should
|
||||
if (m_focusSurface && !pWindowOwner)
|
||||
g_pXWaylandManager->activateSurface(m_focusSurface.lock(), false);
|
||||
|
||||
if (!pSurface) {
|
||||
g_pSeatManager->setKeyboardFocus(nullptr);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = ","});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = ""});
|
||||
EMIT_HOOK_EVENT("keyboardFocus", SP<CWLSurfaceResource>{nullptr});
|
||||
m_focusSurface.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_pSeatManager->m_keyboard)
|
||||
g_pSeatManager->setKeyboardFocus(pSurface);
|
||||
|
||||
if (pWindowOwner)
|
||||
Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", rc<uintptr_t>(pSurface.get()), pWindowOwner);
|
||||
else
|
||||
Debug::log(LOG, "Set keyboard focus to surface {:x}", rc<uintptr_t>(pSurface.get()));
|
||||
|
||||
g_pXWaylandManager->activateSurface(pSurface, true);
|
||||
m_focusSurface = pSurface;
|
||||
|
||||
EMIT_HOOK_EVENT("keyboardFocus", pSurface);
|
||||
|
||||
const auto SURF = CWLSurface::fromResource(pSurface);
|
||||
const auto OLDSURF = CWLSurface::fromResource(PLASTSURF);
|
||||
|
||||
if (OLDSURF && OLDSURF->constraint())
|
||||
OLDSURF->constraint()->deactivate();
|
||||
|
||||
if (SURF && SURF->constraint())
|
||||
SURF->constraint()->activate();
|
||||
}
|
||||
|
||||
void CFocusState::rawMonitorFocus(PHLMONITOR pMonitor) {
|
||||
if (m_focusMonitor == pMonitor)
|
||||
return;
|
||||
|
||||
if (!pMonitor) {
|
||||
m_focusMonitor.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = pMonitor->m_activeWorkspace;
|
||||
|
||||
const auto WORKSPACE_ID = PWORKSPACE ? std::to_string(PWORKSPACE->m_id) : std::to_string(WORKSPACE_INVALID);
|
||||
const auto WORKSPACE_NAME = PWORKSPACE ? PWORKSPACE->m_name : "?";
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "focusedmon", .data = pMonitor->m_name + "," + WORKSPACE_NAME});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "focusedmonv2", .data = pMonitor->m_name + "," + WORKSPACE_ID});
|
||||
|
||||
EMIT_HOOK_EVENT("focusedMon", pMonitor);
|
||||
m_focusMonitor = pMonitor;
|
||||
}
|
||||
|
||||
SP<CWLSurfaceResource> CFocusState::surface() {
|
||||
return m_focusSurface.lock();
|
||||
}
|
||||
|
||||
PHLWINDOW CFocusState::window() {
|
||||
return m_focusWindow.lock();
|
||||
}
|
||||
|
||||
PHLMONITOR CFocusState::monitor() {
|
||||
return m_focusMonitor.lock();
|
||||
}
|
||||
|
||||
const std::vector<PHLWINDOWREF>& CFocusState::windowHistory() {
|
||||
return m_windowFocusHistory;
|
||||
}
|
||||
|
||||
void CFocusState::removeWindowFromHistory(PHLWINDOW w) {
|
||||
std::erase_if(m_windowFocusHistory, [&w](const auto& e) { return !e || e == w; });
|
||||
}
|
||||
|
||||
void CFocusState::addWindowToHistory(PHLWINDOW w) {
|
||||
m_windowFocusHistory.emplace_back(w);
|
||||
}
|
||||
|
||||
void CFocusState::moveWindowToLatestInHistory(PHLWINDOW w) {
|
||||
const auto HISTORYPIVOT = std::ranges::find_if(m_windowFocusHistory, [&w](const auto& other) { return other.lock() == w; });
|
||||
if (HISTORYPIVOT == m_windowFocusHistory.end())
|
||||
Debug::log(TRACE, "CFocusState: {} has no pivot in history, ignoring request to move to latest", w);
|
||||
else
|
||||
std::rotate(m_windowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1);
|
||||
}
|
||||
43
src/desktop/state/FocusState.hpp
Normal file
43
src/desktop/state/FocusState.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "../DesktopTypes.hpp"
|
||||
#include "../../SharedDefs.hpp"
|
||||
|
||||
class CWLSurfaceResource;
|
||||
|
||||
namespace Desktop {
|
||||
class CFocusState {
|
||||
public:
|
||||
CFocusState();
|
||||
~CFocusState() = default;
|
||||
|
||||
CFocusState(CFocusState&&) = delete;
|
||||
CFocusState(CFocusState&) = delete;
|
||||
CFocusState(const CFocusState&) = delete;
|
||||
|
||||
void fullWindowFocus(PHLWINDOW w, SP<CWLSurfaceResource> surface = nullptr, bool preserveFocusHistory = false, bool forceFSCycle = false);
|
||||
void rawWindowFocus(PHLWINDOW w, SP<CWLSurfaceResource> surface = nullptr, bool preserveFocusHistory = false);
|
||||
void rawSurfaceFocus(SP<CWLSurfaceResource> s, PHLWINDOW pWindowOwner = nullptr);
|
||||
void rawMonitorFocus(PHLMONITOR m);
|
||||
|
||||
SP<CWLSurfaceResource> surface();
|
||||
PHLWINDOW window();
|
||||
PHLMONITOR monitor();
|
||||
const std::vector<PHLWINDOWREF>& windowHistory();
|
||||
|
||||
void addWindowToHistory(PHLWINDOW w);
|
||||
|
||||
private:
|
||||
void removeWindowFromHistory(PHLWINDOW w);
|
||||
void moveWindowToLatestInHistory(PHLWINDOW w);
|
||||
|
||||
WP<CWLSurfaceResource> m_focusSurface;
|
||||
PHLWINDOWREF m_focusWindow;
|
||||
PHLMONITORREF m_focusMonitor;
|
||||
std::vector<PHLWINDOWREF> m_windowFocusHistory; // first element is the most recently focused
|
||||
|
||||
SP<HOOK_CALLBACK_FN> m_windowOpen, m_windowClose;
|
||||
};
|
||||
|
||||
SP<CFocusState> focusState();
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue