summaryrefslogtreecommitdiff
path: root/gui-libs/pixdecor/files/pixdecor-focus-flash-property.patch
blob: 330308519c3001596e7dc916aafa66731cf76e16 (plain)
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