opuntiaOS - an operating system targeting x86 and ARMv7
at master 5.4 kB view raw
1/* 2 * Copyright (C) 2020-2022 The opuntiaOS Project Authors. 3 * + Contributed by Nikita Melekhin <nimelehin@gmail.com> 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "Compositor.h" 10#include "Components/Base/BaseWindow.h" 11#include "Components/ControlBar/ControlBar.h" 12#include "Components/MenuBar/MenuBar.h" 13#include "Components/Popup/Popup.h" 14#include "Devices/Screen.h" 15#include "Managers/CursorManager.h" 16#include "Managers/ResourceManager.h" 17#include "Managers/WindowManager.h" 18#include <libfoundation/EventLoop.h> 19#include <libfoundation/Memory.h> 20#include <libg/Context.h> 21 22namespace WinServer { 23 24Compositor* s_WinServer_Compositor_the = nullptr; 25 26Compositor::Compositor() 27 : m_cursor_manager(CursorManager::the()) 28 , m_resource_manager(ResourceManager::the()) 29 , m_popup(Popup::the()) 30 , m_menu_bar(MenuBar::the()) 31#ifdef TARGET_MOBILE 32 , m_control_bar(ControlBar::the()) 33#endif // TARGET_MOBILE 34{ 35 s_WinServer_Compositor_the = this; 36 invalidate(Screen::the().bounds()); 37 LFoundation::EventLoop::the().add(LFoundation::Timer([] { 38 Compositor::the().refresh(); 39 }, 40 1000 / 60, LFoundation::Timer::Repeat)); 41} 42 43void Compositor::copy_changes_to_second_buffer(const std::vector<LG::Rect>& areas) 44{ 45 auto& screen = Screen::the(); 46 47 for (int i = 0; i < areas.size(); i++) { 48 auto bounds = areas[i].intersection(screen.bounds()); 49 auto* buf1_ptr = reinterpret_cast<uint32_t*>(&screen.display_bitmap()[bounds.min_y()][bounds.min_x()]); 50 auto* buf2_ptr = reinterpret_cast<uint32_t*>(&screen.write_bitmap()[bounds.min_y()][bounds.min_x()]); 51 for (int j = 0; j < bounds.height(); j++) { 52 LFoundation::fast_copy(buf2_ptr, buf1_ptr, bounds.width()); 53 buf1_ptr += screen.width(); 54 buf2_ptr += screen.width(); 55 } 56 } 57} 58 59[[gnu::flatten]] void Compositor::refresh() 60{ 61 if (m_invalidated_areas.empty()) { 62 return; 63 } 64 65 auto& screen = Screen::the(); 66 auto& wm = WindowManager::the(); 67 auto invalidated_areas = std::move(m_invalidated_areas); 68 LG::Context ctx(screen.write_bitmap()); 69 70 auto is_window_area_invalidated = [&](const std::vector<LG::Rect>& areas, const LG::Rect& area) -> bool { 71 for (int i = 0; i < areas.size(); i++) { 72 if (area.intersects(areas[i])) { 73 return true; 74 } 75 } 76 return false; 77 }; 78 79 auto draw_wallpaper_for_area = [&](const LG::Rect& area) { 80 ctx.add_clip(area); 81 ctx.draw({ 0, 0 }, m_resource_manager.background()); 82 ctx.reset_clip(); 83 }; 84 85#ifdef TARGET_DESKTOP 86 auto draw_window = [&](Desktop::Window& window, const LG::Rect& area) { 87 ctx.add_clip(area); 88 ctx.add_clip(window.bounds()); 89 window.frame().draw(ctx); 90 ctx.draw_rounded(window.content_bounds().origin(), window.content_bitmap(), window.corner_mask()); 91 ctx.reset_clip(); 92 }; 93#elif TARGET_MOBILE 94 auto draw_window = [&](Mobile::Window& window, const LG::Rect& area) { 95 ctx.add_clip(area); 96 ctx.add_clip(window.bounds()); 97 ctx.draw(window.content_bounds().origin(), window.content_bitmap()); 98 ctx.reset_clip(); 99 }; 100#endif // TARGET_DESKTOP 101 102 auto& windows = wm.windows(); 103 auto top_std_window = windows.rbegin(); 104#ifdef TARGET_DESKTOP 105 for (int i = 0; i < invalidated_areas.size(); i++) { 106 draw_wallpaper_for_area(invalidated_areas[i]); 107 } 108#elif TARGET_MOBILE 109 // Standard windows could not be transparent in mobile view, thus 110 // no need to render everything behind the first standard window. 111 for (auto it = windows.rbegin(); it != windows.rend(); it++) { 112 top_std_window = it; 113 } 114 115 if (top_std_window == windows.rend() || (*top_std_window)->type() != WindowType::Standard) { 116 for (int i = 0; i < invalidated_areas.size(); i++) { 117 draw_wallpaper_for_area(invalidated_areas[i]); 118 } 119 } 120#endif // TARGET_DESKTOP 121 122 for (auto it = top_std_window; it != windows.rend(); it++) { 123 auto& window = *(*it); 124 if (window.visible() && is_window_area_invalidated(invalidated_areas, window.bounds())) { 125 for (int i = 0; i < invalidated_areas.size(); i++) { 126 draw_window(window, invalidated_areas[i]); 127 } 128 } 129 } 130 131 if (m_popup.visible()) { 132 for (int i = 0; i < invalidated_areas.size(); i++) { 133 ctx.add_clip(invalidated_areas[i]); 134 m_popup.draw(ctx); 135 ctx.reset_clip(); 136 } 137 } 138 139 for (int i = 0; i < invalidated_areas.size(); i++) { 140 ctx.add_clip(invalidated_areas[i]); 141 m_menu_bar.draw(ctx); 142 ctx.reset_clip(); 143 } 144 145#ifdef TARGET_MOBILE 146 for (int i = 0; i < invalidated_areas.size(); i++) { 147 ctx.add_clip(invalidated_areas[i]); 148 m_control_bar.draw(ctx); 149 ctx.reset_clip(); 150 } 151#endif // TARGET_MOBILE 152 153 auto mouse_draw_position = m_cursor_manager.draw_position(); 154 auto& current_mouse_bitmap = m_cursor_manager.current_cursor(); 155 for (int i = 0; i < invalidated_areas.size(); i++) { 156 ctx.add_clip(invalidated_areas[i]); 157 ctx.draw(mouse_draw_position, current_mouse_bitmap); 158 ctx.reset_clip(); 159 } 160 161 screen.swap_buffers(); 162 copy_changes_to_second_buffer(invalidated_areas); 163} 164 165} // namespace WinServer