Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix layershell keyboard focus grabs (#4968) #6394

Merged
merged 10 commits into from
Jun 11, 2024
87 changes: 40 additions & 47 deletions src/desktop/LayerSurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ void CLayerSurface::onDestroy() {
void CLayerSurface::onMap() {
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface);

mapped = true;
keyboardExclusive = layerSurface->current.interactivity;
mapped = true;
interactivity = layerSurface->current.interactivity;

// fix if it changed its mon
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
Expand All @@ -133,12 +133,15 @@ void CLayerSurface::onMap() {

surface->resource()->enter(PMONITOR->self.lock());

if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;

if (ISEXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(self);

const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained
(g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained());
const bool GRABSFOCUS = ISEXCLUSIVE ||
(layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained
(g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()));

if (GRABSFOCUS) {
// TODO: use the new superb really very cool grab
Expand Down Expand Up @@ -177,9 +180,6 @@ void CLayerSurface::onUnmap() {

std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });

if (!g_pInputManager->m_dExclusiveLSes.empty())
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource());

if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");

Expand Down Expand Up @@ -210,33 +210,8 @@ void CLayerSurface::onUnmap() {
return;

// refocus if needed
if (WASLASTFOCUS) {
g_pInputManager->releaseAllMouseButtons();

Vector2D surfaceCoords;
PHLLS pFoundLayerSurface;
SP<CWLSurfaceResource> foundSurface = nullptr;

g_pCompositor->m_pLastFocus.reset();

// find LS-es to focus
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
&surfaceCoords, &pFoundLayerSurface);

if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
&surfaceCoords, &pFoundLayerSurface);

if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) {
// if there isn't any, focus the last window
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PLASTWINDOW);
} else {
// otherwise, full refocus
g_pInputManager->refocus();
}
}
if (WASLASTFOCUS)
g_pInputManager->refocusLastWindow(PMONITOR);

CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
Expand Down Expand Up @@ -311,18 +286,36 @@ void CLayerSurface::onCommit() {
realSize.setValueAndWarp(geometry.size());
}

if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained
&& !keyboardExclusive && mapped) {
g_pCompositor->focusSurface(surface->resource());

const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
g_pInputManager->m_bEmptyFocusCursorSet = false;
} else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) {
g_pInputManager->refocus();
if (mapped) {
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;

if (!WASEXCLUSIVE && ISEXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(self);
else if (WASEXCLUSIVE && !ISEXCLUSIVE)
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });

// if the surface was focused and interactive but now isn't, refocus
if (WASLASTFOCUS && !layerSurface->current.interactivity) {
outfoxxed marked this conversation as resolved.
Show resolved Hide resolved
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
// so unfocus the surface here.
g_pCompositor->focusSurface(nullptr);
g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID));
} else if (!WASEXCLUSIVE && !WASLASTFOCUS &&
(ISEXCLUSIVE || (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())))) {
// if not focused last and exclusive or accepting input + unconstrained
g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(surface->resource());

const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
g_pInputManager->m_bEmptyFocusCursorSet = false;
}
}

keyboardExclusive = layerSurface->current.interactivity;
interactivity = layerSurface->current.interactivity;

g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y);

Expand Down Expand Up @@ -512,4 +505,4 @@ int CLayerSurface::popupsCount() {
int no = -1; // we have one dummy
popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no);
return no;
}
}
53 changes: 27 additions & 26 deletions src/desktop/LayerSurface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,40 +34,41 @@ class CLayerSurface {
WP<CLayerShellResource> layerSurface;
wl_list link;

bool keyboardExclusive = false;
// the header providing the enum type cannot be imported here
int interactivity = 0;

SP<CWLSurface> surface;
SP<CWLSurface> surface;

bool mapped = false;
uint32_t layer = 0;
bool mapped = false;
uint32_t layer = 0;

int monitorID = -1;
int monitorID = -1;

bool fadingOut = false;
bool readyToDelete = false;
bool noProcess = false;
bool noAnimations = false;
bool fadingOut = false;
bool readyToDelete = false;
bool noProcess = false;
bool noAnimations = false;

bool forceBlur = false;
bool forceBlurPopups = false;
int xray = -1;
bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f;
bool dimAround = false;
bool forceBlur = false;
bool forceBlurPopups = false;
int xray = -1;
bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f;
bool dimAround = false;

std::optional<std::string> animationStyle;
std::optional<std::string> animationStyle;

PHLLSREF self;
PHLLSREF self;

CBox geometry = {0, 0, 0, 0};
Vector2D position;
std::string szNamespace = "";
std::unique_ptr<CPopup> popupHead;
CBox geometry = {0, 0, 0, 0};
Vector2D position;
std::string szNamespace = "";
std::unique_ptr<CPopup> popupHead;

void onDestroy();
void onMap();
void onUnmap();
void onCommit();
void onDestroy();
void onMap();
void onUnmap();
void onCommit();

private:
struct {
Expand All @@ -83,4 +84,4 @@ class CLayerSurface {
bool operator==(const CLayerSurface& rhs) const {
return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID;
}
};
};
37 changes: 36 additions & 1 deletion src/managers/input/InputManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
}

if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 &&
allowKeyboardRefocus) {
(allowKeyboardRefocus || pFoundLayerSurface->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)) {
g_pCompositor->focusSurface(foundSurface);
}

Expand Down Expand Up @@ -1381,6 +1381,41 @@ void CInputManager::refocus() {
mouseMoveUnified(0, true);
}

void CInputManager::refocusLastWindow(CMonitor* pMonitor) {
if (!pMonitor) {
refocus();
return;
}

Vector2D surfaceCoords;
PHLLS pFoundLayerSurface;
SP<CWLSurfaceResource> foundSurface = nullptr;

g_pInputManager->releaseAllMouseButtons();

// first try for an exclusive layer
if (!m_dExclusiveLSes.empty())
foundSurface = m_dExclusiveLSes[m_dExclusiveLSes.size() - 1]->surface->resource();

// then any surfaces above windows on the same monitor
if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
&surfaceCoords, &pFoundLayerSurface);

if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
&surfaceCoords, &pFoundLayerSurface);

if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) {
// then the last focused window if we're on the same workspace as it
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
g_pCompositor->focusWindow(PLASTWINDOW);
} else {
// otherwise fall back to a normal refocus.
refocus();
}
}

void CInputManager::unconstrainMouse() {
if (g_pSeatManager->mouse.expired())
return;
Expand Down
1 change: 1 addition & 0 deletions src/managers/input/InputManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class CInputManager {

Vector2D getMouseCoordsInternal();
void refocus();
void refocusLastWindow(CMonitor* pMonitor);
void simulateMouseMovement();
void sendMotionEventsToFocused();

Expand Down
Loading