Serenity Operating System
at master 148 lines 4.0 kB view raw
1/* 2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include "WindowStack.h" 8#include "WindowManager.h" 9 10namespace WindowServer { 11 12WindowStack::WindowStack(unsigned row, unsigned column) 13 : m_row(row) 14 , m_column(column) 15{ 16} 17 18void WindowStack::add(Window& window) 19{ 20 VERIFY(!window.is_on_any_window_stack({})); 21 m_windows.append(window); 22 window.set_window_stack({}, this); 23 24 move_always_on_top_windows_to_front(); 25} 26 27void WindowStack::add_to_back(Window& window) 28{ 29 VERIFY(!window.is_on_any_window_stack({})); 30 m_windows.prepend(window); 31 window.set_window_stack({}, this); 32} 33 34void WindowStack::remove(Window& window) 35{ 36 VERIFY(&window.window_stack() == this); 37 m_windows.remove(window); 38 window.set_window_stack({}, nullptr); 39 if (m_active_window == &window) 40 m_active_window = nullptr; 41} 42 43void WindowStack::move_to_front(Window& window) 44{ 45 if (m_windows.last() != &window) 46 window.invalidate(); 47 48 m_windows.remove(window); 49 m_windows.append(window); 50 51 move_always_on_top_windows_to_front(); 52 53 if (window.is_always_on_top()) { 54 m_windows.remove(window); 55 m_windows.append(window); 56 window.invalidate(); 57 } 58} 59 60void WindowStack::move_always_on_top_windows_to_front() 61{ 62 Window::List always_on_top_list; 63 for (auto iterator = m_windows.begin(); iterator != m_windows.end(); ++iterator) { 64 auto& window = *iterator; 65 if (window.is_always_on_top()) { 66 m_windows.remove(window); 67 always_on_top_list.append(window); 68 iterator = m_windows.begin(); 69 } 70 } 71 72 while (!always_on_top_list.is_empty()) { 73 auto& window = *always_on_top_list.begin(); 74 always_on_top_list.remove(window); 75 m_windows.append(window); 76 window.invalidate(); 77 } 78} 79 80void WindowStack::move_all_windows(WindowStack& new_window_stack, Vector<Window*, 32>& windows_moved, MoveAllWindowsTo move_to) 81{ 82 VERIFY(this != &new_window_stack); 83 84 move_always_on_top_windows_to_front(); 85 86 if (move_to == MoveAllWindowsTo::Front) { 87 while (auto* window = m_windows.take_first()) { 88 window->set_window_stack({}, nullptr); 89 new_window_stack.add(*window); 90 windows_moved.append(window); 91 } 92 } else { 93 while (auto* window = m_windows.take_last()) { 94 window->set_window_stack({}, nullptr); 95 new_window_stack.add_to_back(*window); 96 windows_moved.append(window); 97 } 98 } 99 m_active_window = nullptr; 100} 101 102Window* WindowStack::window_at(Gfx::IntPoint position, IncludeWindowFrame include_window_frame) const 103{ 104 auto result = hit_test(position); 105 if (!result.has_value()) 106 return nullptr; 107 if (include_window_frame == IncludeWindowFrame::No && result->is_frame_hit) 108 return nullptr; 109 return result->window; 110} 111 112Window* WindowStack::highlight_window() const 113{ 114 if (auto* window = WindowManager::the().highlight_window(); window && &window->window_stack() == this) 115 return window; 116 return nullptr; 117} 118 119void WindowStack::set_active_window(Window* window) 120{ 121 if (!window) 122 m_active_window = nullptr; 123 else 124 m_active_window = window->make_weak_ptr<Window>(); 125} 126 127void WindowStack::set_all_occluded(bool occluded) 128{ 129 for (auto& window : m_windows) { 130 if (!WindowManager::is_stationary_window_type(window.type())) 131 window.set_occluded(occluded); 132 } 133} 134 135Optional<HitTestResult> WindowStack::hit_test(Gfx::IntPoint position) const 136{ 137 Optional<HitTestResult> result; 138 WindowManager::the().for_each_visible_window_from_front_to_back([&](Window& window) { 139 result = window.hit_test(position); 140 if (result.has_value()) 141 return IterationDecision::Break; 142 return IterationDecision::Continue; 143 }, 144 const_cast<WindowStack*>(this)); 145 return result; 146} 147 148}