From 9da30cb20105792bc69a78082f537346efe7699f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 15:40:50 -0600 Subject: [PATCH] focus-flash: per-window opt-out through the pixdecor-focus-flash view property Another plugin can keep a window from flashing: "none" never flashes it (a drawer window), "skip-once" skips the next focus change to it and is then erased (the window a closing drawer hands focus back to). Co-Authored-By: Claude Opus 5.5 --- src/decoration.cpp | 7 +++++++ src/focus-flash.hpp | 8 +++++++- tests/focus-flash-test.cpp | 8 ++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/decoration.cpp b/src/decoration.cpp index 8bbf7e3..ee261d8 100644 --- a/src/decoration.cpp +++ b/src/decoration.cpp @@ -105,6 +105,13 @@ class wayfire_pixdecor : public wf::plugin_interface_t auto under = at ? wf::toplevel_cast(wf::node_to_view(at->node.get())) : nullptr; change.under_pointer = same_window(under, view); change.pointer_too = focus_flash_pointer; + auto opt_out = view->get_property(focus_flash::opt_out_property); + if (opt_out == "skip-once") + { + view->erase_property(focus_flash::opt_out_property); + } + + change.opted_out = (opt_out == "none") || (opt_out == "skip-once"); if (focus_flash::should_flash(change)) { deco->flash(); diff --git a/src/focus-flash.hpp b/src/focus-flash.hpp index 68de131..42e1e70 100644 --- a/src/focus-flash.hpp +++ b/src/focus-flash.hpp @@ -19,13 +19,19 @@ struct change_t bool just_mapped = false; // the window appeared moments ago: opening is cue enough bool under_pointer = false; // the pointer is over the window: clicked, or hovered with follow-focus bool pointer_too = false; // pixdecor/focus_flash_pointer: flash those as well + bool opted_out = false; // the window's "pixdecor-focus-flash" property says not to (a drawer, say) }; inline bool should_flash(const change_t& c) { - return c.enabled && c.framed && !c.same_window && !c.just_mapped && (!c.under_pointer || c.pointer_too); + return c.enabled && c.framed && !c.same_window && !c.just_mapped && !c.opted_out && + (!c.under_pointer || c.pointer_too); } +// View property another plugin sets to keep a window from flashing: "none" (never) or "skip-once" (not on +// the next focus change to it; pixdecor then erases it). +inline constexpr const char *opt_out_property = "pixdecor-focus-flash"; + // How long after mapping a window's first focus counts as part of opening it. inline constexpr double map_grace_ms = 1000; diff --git a/tests/focus-flash-test.cpp b/tests/focus-flash-test.cpp index f37804b..0a1de8b 100644 --- a/tests/focus-flash-test.cpp +++ b/tests/focus-flash-test.cpp @@ -58,6 +58,14 @@ int main() c.framed = false; assert(!should_flash(c)); + // Opted out by another plugin (a drawer window, or the window a closing drawer hands focus back to), + // also with pointer focus flashing. + c = keyboard_switch(); + c.opted_out = true; + assert(!should_flash(c)); + c.under_pointer = c.pointer_too = true; + assert(!should_flash(c)); + // Strength: full, held for 30%, eased to nothing, then off. assert(level(0, 550) == 1); assert(level(165, 550) == 1); -- 2.56.0