Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/server/focus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ namespace umbriel {
m_server.registry().promote(view);
view->setUrgent(false);

if (reason == FocusReason::XdgActivation || reason == FocusReason::ForeignActivation) {
view->applyDeferredUnfullscreen();
}

// Keep workspace focus while exclusive layer-shell holds the seat; refocus applies it later. Still clear activation
// chrome so the previous window does not stay visually focused. Overview owns the seat the same way, but keeps the
// chrome so card borders track the focused window; the keyboard enter replays when it closes.
Expand Down
25 changes: 24 additions & 1 deletion src/view/view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "view/xdg_size.h"
// clang-format off
#include <algorithm>
#include <chrono>
#include <cmath>
#include "wlr.h"
// clang-format on
Expand Down Expand Up @@ -1813,8 +1814,10 @@ namespace umbriel {
// fullscreen strip the moment the user scrolls away. Deny unfullscreen from deactivated windows; the scheduled
// configure re-asserts the fullscreen state (spec-compliant).
if (!requested && !m_toplevel->scheduled.activated) {
m_deferredUnfullscreen = true;
m_deferredUnfullscreenAt = std::chrono::steady_clock::now();
kLog.debug(
"request_fullscreen denied for deactivated '{}'", m_toplevel->app_id != nullptr ? m_toplevel->app_id : "?"
"request_fullscreen parked for deactivated '{}'", m_toplevel->app_id != nullptr ? m_toplevel->app_id : "?"
);
wlr_xdg_surface_schedule_configure(m_toplevel->base);
return;
Expand All @@ -1840,6 +1843,25 @@ namespace umbriel {
setFullscreen(!m_toplevel->scheduled.fullscreen);
}

void View::applyDeferredUnfullscreen() {
constexpr auto kDeferredUnfullscreenGrace = std::chrono::milliseconds(750);
if (!m_deferredUnfullscreen) {
return;
}
m_deferredUnfullscreen = false;
if (!m_toplevel->base->initialized
|| std::chrono::steady_clock::now() - m_deferredUnfullscreenAt > kDeferredUnfullscreenGrace) {
return;
}
if (m_toplevel->scheduled.fullscreen || m_toplevel->current.fullscreen) {
kLog.debug(
"deferred unfullscreen applied on activation for '{}'",
m_toplevel->app_id != nullptr ? m_toplevel->app_id : "?"
);
setFullscreen(false);
}
}

void View::toggleFloating() { setFloating(m_tiled); }

void View::restorePinnedSceneParent() {
Expand Down Expand Up @@ -2081,6 +2103,7 @@ namespace umbriel {
}

void View::setFullscreen(bool fullscreen) {
m_deferredUnfullscreen = false;
kLog.debug(
"set_fullscreen '{}' [{}] -> {} (tiled={}, ws_active={})",
m_toplevel->app_id != nullptr ? m_toplevel->app_id : "?", static_cast<const void*>(this), fullscreen, m_tiled,
Expand Down
3 changes: 3 additions & 0 deletions src/view/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ namespace umbriel {
void applyFullscreenLayout(bool animate = false);
// Compositor-driven fullscreen toggle (keybind); client requests use handleRequestFullscreen.
void toggleFullscreen();
void applyDeferredUnfullscreen();
void setMaximizedToEdges(bool maximized);
void toggleMaximizedToEdges();
// Detach from the scrolling layout (float) or re-insert as a tiled column.
Expand Down Expand Up @@ -326,6 +327,8 @@ namespace umbriel {
// 0 until the first frame tick after arming; the grace deadline counts
// from there so a stalled frame clock cannot expire it instantly.
uint64_t m_unfullscreenGraceStartMsec = 0;
bool m_deferredUnfullscreen = false;
std::chrono::steady_clock::time_point m_deferredUnfullscreenAt{};
// Geometry at unfullscreen time; a commit with a different geometry means
// the client accepted windowed mode and the grace can end early.
wlr_box m_unfullscreenGeometry{};
Expand Down