Skip to content

Commit

Permalink
layershell: Fix keyboard focus grabs (#4968) (#6394)
Browse files Browse the repository at this point in the history
  • Loading branch information
outfoxxed committed Jun 11, 2024
1 parent 1c388e5 commit 21b9e31
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 74 deletions.
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) {
// 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 @@ -512,7 +512,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 @@ -1384,6 +1384,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

0 comments on commit 21b9e31

Please sign in to comment.