Serenity Operating System
1/*
2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2021, networkException <networkexception@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include "Window.h"
11
12namespace WindowServer {
13
14class Compositor;
15
16class WindowStack {
17public:
18 WindowStack(unsigned row, unsigned column);
19 ~WindowStack() = default;
20
21 bool is_empty() const { return m_windows.is_empty(); }
22 void add(Window&);
23 void add_to_back(Window&);
24 void remove(Window&);
25 void move_to_front(Window&);
26 void move_always_on_top_windows_to_front();
27
28 enum class MoveAllWindowsTo {
29 Front,
30 Back
31 };
32 void move_all_windows(WindowStack&, Vector<Window*, 32>&, MoveAllWindowsTo);
33
34 enum class IncludeWindowFrame {
35 Yes,
36 No,
37 };
38 Window* window_at(Gfx::IntPoint, IncludeWindowFrame = IncludeWindowFrame::Yes) const;
39 Window* highlight_window() const;
40
41 template<typename Callback>
42 IterationDecision for_each_visible_window_of_type_from_front_to_back(WindowType, Callback, bool ignore_highlight = false);
43 template<typename Callback>
44 IterationDecision for_each_visible_window_of_type_from_back_to_front(WindowType, Callback, bool ignore_highlight = false);
45 template<typename Callback>
46 IterationDecision for_each_window_of_type_from_front_to_back(WindowType, Callback, bool ignore_highlight = false);
47
48 template<typename Callback>
49 void for_each_window(Callback);
50 template<typename Callback>
51 IterationDecision for_each_window_from_back_to_front(Callback);
52
53 Window::List& windows() { return m_windows; }
54
55 Window* active_window() { return m_active_window; }
56 Window const* active_window() const { return m_active_window; }
57 void set_active_window(Window*);
58
59 Optional<HitTestResult> hit_test(Gfx::IntPoint) const;
60
61 unsigned row() const { return m_row; }
62 unsigned column() const { return m_column; }
63
64 void set_transition_offset(Badge<Compositor>, Gfx::IntPoint transition_offset) { m_transition_offset = transition_offset; }
65 Gfx::IntPoint transition_offset() const { return m_transition_offset; }
66
67 void set_stationary_window_stack(WindowStack& window_stack) { m_stationary_window_stack = &window_stack; }
68 WindowStack& stationary_window_stack()
69 {
70 VERIFY(m_stationary_window_stack);
71 return *m_stationary_window_stack;
72 }
73
74 void set_all_occluded(bool);
75
76private:
77 WeakPtr<Window> m_active_window;
78
79 Window::List m_windows;
80 unsigned m_row { 0 };
81 unsigned m_column { 0 };
82 Gfx::IntPoint m_transition_offset;
83 WindowStack* m_stationary_window_stack { nullptr };
84};
85
86template<typename Callback>
87inline IterationDecision WindowStack::for_each_visible_window_of_type_from_back_to_front(WindowType type, Callback callback, bool ignore_highlight)
88{
89 auto* highlight_window = this->highlight_window();
90 bool do_highlight_window_at_end = false;
91 for (auto& window : m_windows) {
92 if (!window.is_visible())
93 continue;
94 if (window.is_minimized())
95 continue;
96 if (window.type() != type)
97 continue;
98 if (!ignore_highlight && highlight_window == &window) {
99 do_highlight_window_at_end = true;
100 continue;
101 }
102 if (callback(window) == IterationDecision::Break)
103 return IterationDecision::Break;
104 }
105 if (do_highlight_window_at_end) {
106 if (callback(*highlight_window) == IterationDecision::Break)
107 return IterationDecision::Break;
108 }
109 return IterationDecision::Continue;
110}
111
112template<typename Callback>
113inline IterationDecision WindowStack::for_each_visible_window_of_type_from_front_to_back(WindowType type, Callback callback, bool ignore_highlight)
114{
115 auto* highlight_window = this->highlight_window();
116 if (!ignore_highlight && highlight_window && highlight_window->type() == type && highlight_window->is_visible() && !highlight_window->is_minimized()) {
117 if (callback(*highlight_window) == IterationDecision::Break)
118 return IterationDecision::Break;
119 }
120
121 auto reverse_iterator = m_windows.rbegin();
122 for (; reverse_iterator != m_windows.rend(); ++reverse_iterator) {
123 auto& window = *reverse_iterator;
124 if (!window.is_visible())
125 continue;
126 if (window.is_minimized())
127 continue;
128 if (window.type() != type)
129 continue;
130 if (!ignore_highlight && &window == highlight_window)
131 continue;
132 if (callback(window) == IterationDecision::Break)
133 return IterationDecision::Break;
134 }
135 return IterationDecision::Continue;
136}
137
138template<typename Callback>
139inline void WindowStack::for_each_window(Callback callback)
140{
141 auto reverse_iterator = m_windows.rbegin();
142 for (; reverse_iterator != m_windows.rend(); ++reverse_iterator) {
143 auto& window = *reverse_iterator;
144 if (callback(window) == IterationDecision::Break)
145 return;
146 }
147}
148
149template<typename Callback>
150inline IterationDecision WindowStack::for_each_window_from_back_to_front(Callback callback)
151{
152 for (auto& window : m_windows) {
153 IterationDecision decision = callback(window);
154 if (decision != IterationDecision::Break)
155 return decision;
156 }
157 return IterationDecision::Continue;
158}
159
160template<typename Callback>
161inline IterationDecision WindowStack::for_each_window_of_type_from_front_to_back(WindowType type, Callback callback, bool ignore_highlight)
162{
163 auto* highlight_window = this->highlight_window();
164 if (!ignore_highlight && highlight_window && highlight_window->type() == type && highlight_window->is_visible()) {
165 if (callback(*highlight_window) == IterationDecision::Break)
166 return IterationDecision::Break;
167 }
168
169 auto reverse_iterator = m_windows.rbegin();
170 for (; reverse_iterator != m_windows.rend(); ++reverse_iterator) {
171 auto& window = *reverse_iterator;
172 if (window.type() != type)
173 continue;
174 if (!ignore_highlight && &window == highlight_window)
175 continue;
176 if (callback(window) == IterationDecision::Break)
177 return IterationDecision::Break;
178 }
179 return IterationDecision::Continue;
180}
181
182}