1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
From 9da30cb20105792bc69a78082f537346efe7699f Mon Sep 17 00:00:00 2001
From: Claude <noreply@anthropic.com>
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 <noreply@anthropic.com>
---
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<std::string>(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
|