srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/state/tick.rs
blob: 6ef0ed65635c85aad8f5d0f886d62e5f6a0701d9 (plain) (blame)
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
use super::*;

impl CompState {

    /// Re-broadcasts any dock/panel-facing protocol state that changed by a
    /// path with no direct hook back into this module - specifically a
    /// compositor keybinding via `crates/config`'s `WindowAction`/
    /// `srd.workspace.*` API, which only ever touches `WindowManager` and
    /// has no way to reach `CompState`. See `foreign_toplevel::
    /// broadcast_dirty_state` and `workspace::broadcast_dirty_active`'s own
    /// doc comments for the full story; called once per frame alongside
    /// `tick_animations`, from both backends' poll loops.
    pub(crate) fn tick_dirty_broadcasts(&mut self) {
        foreign_toplevel::broadcast_dirty_state(self);
        workspace::broadcast_dirty_active(self);
        output_management::broadcast_dirty_outputs(self);
    }

    /// Advances every in-flight `WindowAnim` by one frame; called once per
    /// redraw from both backends' poll loops. A finished tween is dropped
    /// *before* its final `sync_geometry` call, so that call lands exactly
    /// on `Window.geometry` (the authoritative target) rather than on
    /// whatever the eased curve's last sub-pixel step happened to be.
    pub(crate) fn tick_animations(&mut self) {
        if self.window_anims.is_empty() {
            return;
        }
        let ids: Vec<WindowId> = self.window_anims.keys().copied().collect();
        for id in ids {
            if self.window_anims.get(&id).is_some_and(WindowAnim::is_done) {
                self.window_anims.remove(&id);
            }
            self.sync_geometry(id);
        }
    }

    /// Re-applies `WindowManager`'s own stacking order to `Space`, bottom
    /// to top.
    ///
    /// `Space::map_element` (smithay 0.7.0) always re-stacks its target to
    /// the top of `Space`'s internal order as an unconditional side effect
    /// of updating its tracked position - true regardless of the
    /// `activate` argument, and there is no "move without restacking" in
    /// this smithay version. `sync_geometry` calls `map_element` for
    /// reasons that have nothing to do with raising a window at all (a
    /// title/app_id changing, an ordinary resize frame, a workspace
    /// switch), so every one of those silently raised the window it
    /// touched to the top of `Space`'s order regardless of which window
    /// `WindowManager`/the user actually considered focused or on top.
    /// Real-world effect, confirmed live: two windows created moments
    /// apart, each independently going through their own startup
    /// title/app_id negotiation, would each trigger a handful of
    /// `sync_geometry` calls purely from that startup sequence - so
    /// whichever one happened to settle *last* silently won `Space`'s
    /// notion of "on top", a race with no relationship to which window was
    /// actually focused. Reported live as a background window's content
    /// and decoration randomly painting in front of the actually-focused
    /// window on top of it. Calling this right after any `map_element`
    /// restores `Space`'s order to exactly match `WindowManager.order`
    /// (which `restack_pinned` already keeps pinned windows at the tail
    /// of), so the two can never drift apart again.
    pub(crate) fn resync_stacking_order(&mut self) {
        let order: Vec<WindowId> = self.wm.borrow().stacking_order().map(|w| w.id).collect();
        for id in order {
            if let Some(w) = self.id_to_window.get(&id).cloned() {
                self.space.raise_element(&w, false);
            }
        }
    }
}