Compositor.cpp 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784
  1. /*
  2. * Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Compositor.h"
  7. #include "Animation.h"
  8. #include "ConnectionFromClient.h"
  9. #include "Event.h"
  10. #include "EventLoop.h"
  11. #include "MultiScaleBitmaps.h"
  12. #include "Screen.h"
  13. #include "Window.h"
  14. #include "WindowManager.h"
  15. #include "WindowSwitcher.h"
  16. #include <AK/Debug.h>
  17. #include <AK/Memory.h>
  18. #include <AK/ScopeGuard.h>
  19. #include <AK/TemporaryChange.h>
  20. #include <LibCore/Timer.h>
  21. #include <LibGfx/AntiAliasingPainter.h>
  22. #include <LibGfx/Font/Font.h>
  23. #include <LibGfx/Painter.h>
  24. #include <LibGfx/StylePainter.h>
  25. #include <LibThreading/BackgroundAction.h>
  26. namespace WindowServer {
  27. Compositor& Compositor::the()
  28. {
  29. static Compositor s_the;
  30. return s_the;
  31. }
  32. static WallpaperMode mode_to_enum(DeprecatedString const& name)
  33. {
  34. if (name == "Tile")
  35. return WallpaperMode::Tile;
  36. if (name == "Stretch")
  37. return WallpaperMode::Stretch;
  38. if (name == "Center")
  39. return WallpaperMode::Center;
  40. return WallpaperMode::Center;
  41. }
  42. Compositor::Compositor()
  43. {
  44. m_display_link_notify_timer = add<Core::Timer>(
  45. 1000 / 60, [this] {
  46. notify_display_links();
  47. });
  48. m_compose_timer = Core::Timer::create_single_shot(
  49. 1000 / 60,
  50. [this] {
  51. compose();
  52. },
  53. this)
  54. .release_value_but_fixme_should_propagate_errors();
  55. m_compose_timer->start();
  56. m_immediate_compose_timer = Core::Timer::create_single_shot(
  57. 0,
  58. [this] {
  59. compose();
  60. },
  61. this)
  62. .release_value_but_fixme_should_propagate_errors();
  63. m_compose_timer->start();
  64. init_bitmaps();
  65. }
  66. Gfx::Bitmap const* Compositor::cursor_bitmap_for_screenshot(Badge<ConnectionFromClient>, Screen& screen) const
  67. {
  68. if (!m_current_cursor)
  69. return nullptr;
  70. return &m_current_cursor->bitmap(screen.scale_factor());
  71. }
  72. Gfx::Bitmap const& Compositor::front_bitmap_for_screenshot(Badge<ConnectionFromClient>, Screen& screen) const
  73. {
  74. return *screen.compositor_screen_data().m_front_bitmap;
  75. }
  76. Gfx::Color Compositor::color_at_position(Badge<ConnectionFromClient>, Screen& screen, Gfx::IntPoint position) const
  77. {
  78. return screen.compositor_screen_data().m_front_bitmap->get_pixel(position);
  79. }
  80. void CompositorScreenData::init_bitmaps(Compositor& compositor, Screen& screen)
  81. {
  82. // Recreate the screen-number overlay as the Screen instances may have changed, or get rid of it if we no longer need it
  83. if (compositor.showing_screen_numbers()) {
  84. m_screen_number_overlay = compositor.create_overlay<ScreenNumberOverlay>(screen);
  85. m_screen_number_overlay->set_enabled(true);
  86. } else {
  87. m_screen_number_overlay = nullptr;
  88. }
  89. m_has_flipped = false;
  90. m_have_flush_rects = false;
  91. m_buffers_are_flipped = false;
  92. m_screen_can_set_buffer = screen.can_set_buffer();
  93. m_flush_rects.clear_with_capacity();
  94. m_flush_transparent_rects.clear_with_capacity();
  95. m_flush_special_rects.clear_with_capacity();
  96. auto size = screen.size();
  97. m_front_bitmap = nullptr;
  98. m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor(), screen.pitch(), screen.scanline(0, 0)).release_value_but_fixme_should_propagate_errors();
  99. m_front_painter = make<Gfx::Painter>(*m_front_bitmap);
  100. m_front_painter->translate(-screen.rect().location());
  101. m_back_bitmap = nullptr;
  102. if (m_screen_can_set_buffer)
  103. m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor(), screen.pitch(), screen.scanline(1, 0)).release_value_but_fixme_should_propagate_errors();
  104. else
  105. m_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor()).release_value_but_fixme_should_propagate_errors();
  106. m_back_painter = make<Gfx::Painter>(*m_back_bitmap);
  107. m_back_painter->translate(-screen.rect().location());
  108. m_temp_bitmap = nullptr;
  109. m_temp_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, size, screen.scale_factor()).release_value_but_fixme_should_propagate_errors();
  110. m_temp_painter = make<Gfx::Painter>(*m_temp_bitmap);
  111. m_temp_painter->translate(-screen.rect().location());
  112. clear_wallpaper_bitmap();
  113. }
  114. void Compositor::init_bitmaps()
  115. {
  116. Screen::for_each([&](auto& screen) {
  117. screen.compositor_screen_data().init_bitmaps(*this, screen);
  118. return IterationDecision::Continue;
  119. });
  120. invalidate_screen();
  121. }
  122. void Compositor::did_construct_window_manager(Badge<WindowManager>)
  123. {
  124. auto& wm = WindowManager::the();
  125. m_current_window_stack = &wm.current_window_stack();
  126. m_wallpaper_mode = mode_to_enum(g_config->read_entry("Background", "Mode", "Center"));
  127. m_custom_background_color = Color::from_string(g_config->read_entry("Background", "Color", ""));
  128. invalidate_screen();
  129. invalidate_occlusions();
  130. compose();
  131. }
  132. Gfx::IntPoint Compositor::window_transition_offset(Window& window)
  133. {
  134. if (WindowManager::is_stationary_window_type(window.type()))
  135. return {};
  136. if (window.is_moving_to_another_stack())
  137. return {};
  138. return window.window_stack().transition_offset();
  139. }
  140. void Compositor::compose()
  141. {
  142. auto& wm = WindowManager::the();
  143. {
  144. auto& current_cursor = wm.active_cursor();
  145. if (m_current_cursor != &current_cursor) {
  146. change_cursor(&current_cursor);
  147. m_invalidated_cursor = m_invalidated_any = true;
  148. }
  149. }
  150. if (!m_invalidated_any) {
  151. // nothing dirtied since the last compose pass.
  152. return;
  153. }
  154. if (m_occlusions_dirty) {
  155. m_occlusions_dirty = false;
  156. recompute_occlusions();
  157. }
  158. // We should have recomputed occlusions if any overlay rects were changed
  159. VERIFY(!m_overlay_rects_changed);
  160. auto dirty_screen_rects = move(m_dirty_screen_rects);
  161. bool window_stack_transition_in_progress = m_transitioning_to_window_stack != nullptr;
  162. // Mark window regions as dirty that need to be re-rendered
  163. wm.for_each_visible_window_from_back_to_front([&](Window& window) {
  164. auto transition_offset = window_transition_offset(window);
  165. auto frame_rect = window.frame().render_rect();
  166. auto frame_rect_on_screen = frame_rect.translated(transition_offset);
  167. for (auto& dirty_rect : dirty_screen_rects.rects()) {
  168. auto invalidate_rect = dirty_rect.intersected(frame_rect_on_screen);
  169. if (!invalidate_rect.is_empty()) {
  170. auto inner_rect_offset = window.rect().location() - frame_rect.location();
  171. invalidate_rect.translate_by(-(frame_rect.location() + inner_rect_offset + transition_offset));
  172. window.invalidate_no_notify(invalidate_rect);
  173. m_invalidated_window = true;
  174. }
  175. }
  176. window.prepare_dirty_rects();
  177. if (window_stack_transition_in_progress)
  178. window.dirty_rects().translate_by(transition_offset);
  179. return IterationDecision::Continue;
  180. });
  181. // Any dirty rects in transparency areas may require windows above or below
  182. // to also be marked dirty in these areas
  183. wm.for_each_visible_window_from_back_to_front([&](Window& window) {
  184. auto& dirty_rects = window.dirty_rects(); // dirty rects have already been adjusted for transition offset!
  185. if (dirty_rects.is_empty())
  186. return IterationDecision::Continue;
  187. auto& affected_transparency_rects = window.affected_transparency_rects();
  188. if (affected_transparency_rects.is_empty())
  189. return IterationDecision::Continue;
  190. // If we have transparency rects that affect others, we better have transparency rects ourselves...
  191. auto& transparency_rects = window.transparency_rects();
  192. VERIFY(!transparency_rects.is_empty());
  193. for (auto& it : affected_transparency_rects) {
  194. auto& affected_window_dirty_rects = it.key->dirty_rects();
  195. auto& affected_rects = it.value;
  196. affected_rects.for_each_intersected(dirty_rects, [&](auto& dirty_rect) {
  197. affected_window_dirty_rects.add(dirty_rect);
  198. return IterationDecision::Continue;
  199. });
  200. }
  201. return IterationDecision::Continue;
  202. });
  203. Color background_color = wm.palette().desktop_background();
  204. if (m_custom_background_color.has_value())
  205. background_color = m_custom_background_color.value();
  206. if constexpr (COMPOSE_DEBUG) {
  207. dbgln("COMPOSE: invalidated: window: {} cursor: {}, any: {}", m_invalidated_window, m_invalidated_cursor, m_invalidated_any);
  208. for (auto& r : dirty_screen_rects.rects())
  209. dbgln("dirty screen: {}", r);
  210. }
  211. auto& cursor_screen = ScreenInput::the().cursor_location_screen();
  212. Screen::for_each([&](auto& screen) {
  213. auto& screen_data = screen.compositor_screen_data();
  214. screen_data.m_have_flush_rects = false;
  215. screen_data.m_flush_rects.clear_with_capacity();
  216. screen_data.m_flush_transparent_rects.clear_with_capacity();
  217. screen_data.m_flush_special_rects.clear_with_capacity();
  218. return IterationDecision::Continue;
  219. });
  220. auto cursor_rect = current_cursor_rect();
  221. bool need_to_draw_cursor = false;
  222. Gfx::IntRect previous_cursor_rect;
  223. Screen* previous_cursor_screen = nullptr;
  224. auto check_restore_cursor_back = [&](Screen& screen, Gfx::IntRect const& rect) {
  225. if (&screen == &cursor_screen && !previous_cursor_screen && !need_to_draw_cursor && rect.intersects(cursor_rect)) {
  226. // Restore what's behind the cursor if anything touches the area of the cursor
  227. need_to_draw_cursor = true;
  228. if (cursor_screen.compositor_screen_data().restore_cursor_back(cursor_screen, previous_cursor_rect))
  229. previous_cursor_screen = &screen;
  230. }
  231. };
  232. if (&cursor_screen != m_current_cursor_screen) {
  233. // Cursor moved to another screen, restore on the cursor's background on the previous screen
  234. need_to_draw_cursor = true;
  235. if (m_current_cursor_screen) {
  236. if (m_current_cursor_screen->compositor_screen_data().restore_cursor_back(*m_current_cursor_screen, previous_cursor_rect))
  237. previous_cursor_screen = m_current_cursor_screen;
  238. }
  239. m_current_cursor_screen = &cursor_screen;
  240. }
  241. auto prepare_rect = [&](Screen& screen, Gfx::IntRect const& rect) {
  242. auto& screen_data = screen.compositor_screen_data();
  243. dbgln_if(COMPOSE_DEBUG, " -> flush opaque: {}", rect);
  244. VERIFY(!screen_data.m_flush_rects.intersects(rect));
  245. VERIFY(!screen_data.m_flush_transparent_rects.intersects(rect));
  246. screen_data.m_have_flush_rects = true;
  247. screen_data.m_flush_rects.add(rect);
  248. check_restore_cursor_back(screen, rect);
  249. };
  250. auto prepare_transparency_rect = [&](Screen& screen, Gfx::IntRect const& rect) {
  251. auto& screen_data = screen.compositor_screen_data();
  252. dbgln_if(COMPOSE_DEBUG, " -> flush transparent: {}", rect);
  253. VERIFY(!screen_data.m_flush_rects.intersects(rect));
  254. for (auto& r : screen_data.m_flush_transparent_rects.rects()) {
  255. if (r == rect)
  256. return;
  257. }
  258. screen_data.m_have_flush_rects = true;
  259. screen_data.m_flush_transparent_rects.add(rect);
  260. check_restore_cursor_back(screen, rect);
  261. };
  262. if (!cursor_screen.compositor_screen_data().m_cursor_back_bitmap || m_invalidated_cursor)
  263. check_restore_cursor_back(cursor_screen, cursor_rect);
  264. auto paint_wallpaper = [&](Screen& screen, Gfx::Painter& painter, Gfx::IntRect const& rect, Gfx::IntRect const& screen_rect) {
  265. if (m_wallpaper) {
  266. if (m_wallpaper_mode == WallpaperMode::Center) {
  267. Gfx::IntPoint offset { (screen.width() - m_wallpaper->width()) / 2, (screen.height() - m_wallpaper->height()) / 2 };
  268. // FIXME: If the wallpaper is opaque and covers the whole rect, no need to fill with color!
  269. painter.fill_rect(rect, background_color);
  270. painter.blit_offset(rect.location(), *m_wallpaper, rect.translated(-screen_rect.location()), offset);
  271. } else if (m_wallpaper_mode == WallpaperMode::Tile) {
  272. painter.draw_tiled_bitmap(rect, *m_wallpaper);
  273. } else if (m_wallpaper_mode == WallpaperMode::Stretch) {
  274. VERIFY(screen.compositor_screen_data().m_wallpaper_bitmap);
  275. painter.blit(rect.location(), *screen.compositor_screen_data().m_wallpaper_bitmap, rect.translated(-screen.location()));
  276. } else {
  277. VERIFY_NOT_REACHED();
  278. }
  279. } else {
  280. painter.fill_rect(rect, background_color);
  281. }
  282. };
  283. {
  284. // Paint any desktop wallpaper rects that are not somehow underneath any window transparency
  285. // rects and outside of any opaque window areas
  286. m_opaque_wallpaper_rects.for_each_intersected(dirty_screen_rects, [&](auto& render_rect) {
  287. Screen::for_each([&](auto& screen) {
  288. auto screen_rect = screen.rect();
  289. auto screen_render_rect = screen_rect.intersected(render_rect);
  290. if (!screen_render_rect.is_empty()) {
  291. dbgln_if(COMPOSE_DEBUG, " render wallpaper opaque: {} on screen #{}", screen_render_rect, screen.index());
  292. prepare_rect(screen, render_rect);
  293. auto& back_painter = *screen.compositor_screen_data().m_back_painter;
  294. paint_wallpaper(screen, back_painter, render_rect, screen_rect);
  295. }
  296. return IterationDecision::Continue;
  297. });
  298. return IterationDecision::Continue;
  299. });
  300. m_transparent_wallpaper_rects.for_each_intersected(dirty_screen_rects, [&](auto& render_rect) {
  301. Screen::for_each([&](auto& screen) {
  302. auto screen_rect = screen.rect();
  303. auto screen_render_rect = screen_rect.intersected(render_rect);
  304. if (!screen_render_rect.is_empty()) {
  305. dbgln_if(COMPOSE_DEBUG, " render wallpaper transparent: {} on screen #{}", screen_render_rect, screen.index());
  306. prepare_transparency_rect(screen, render_rect);
  307. auto& temp_painter = *screen.compositor_screen_data().m_temp_painter;
  308. paint_wallpaper(screen, temp_painter, render_rect, screen_rect);
  309. }
  310. return IterationDecision::Continue;
  311. });
  312. return IterationDecision::Continue;
  313. });
  314. }
  315. auto compose_window = [&](Window& window) -> IterationDecision {
  316. if (window.screens().is_empty()) {
  317. // This window doesn't intersect with any screens, so there's nothing to render
  318. return IterationDecision::Continue;
  319. }
  320. auto transition_offset = window_transition_offset(window);
  321. auto frame_rect = window.frame().render_rect().translated(transition_offset);
  322. auto window_rect = window.rect().translated(transition_offset);
  323. auto frame_rects = frame_rect.shatter(window_rect);
  324. dbgln_if(COMPOSE_DEBUG, " window {} frame rect: {}", window.title(), frame_rect);
  325. RefPtr<Gfx::Bitmap> backing_store = window.backing_store();
  326. auto compose_window_rect = [&](Screen& screen, Gfx::Painter& painter, const Gfx::IntRect& rect) {
  327. if (!window.is_fullscreen()) {
  328. rect.for_each_intersected(frame_rects, [&](const Gfx::IntRect& intersected_rect) {
  329. Gfx::PainterStateSaver saver(painter);
  330. painter.add_clip_rect(intersected_rect);
  331. painter.translate(transition_offset);
  332. dbgln_if(COMPOSE_DEBUG, " render frame: {}", intersected_rect);
  333. window.frame().paint(screen, painter, intersected_rect.translated(-transition_offset));
  334. return IterationDecision::Continue;
  335. });
  336. }
  337. auto update_window_rect = window_rect.intersected(rect);
  338. if (update_window_rect.is_empty())
  339. return;
  340. auto clear_window_rect = [&](const Gfx::IntRect& clear_rect) {
  341. auto fill_color = wm.palette().window();
  342. if (!window.is_opaque())
  343. fill_color.set_alpha(255 * window.opacity());
  344. painter.fill_rect(clear_rect, fill_color);
  345. };
  346. if (!backing_store) {
  347. clear_window_rect(update_window_rect);
  348. return;
  349. }
  350. // Decide where we would paint this window's backing store.
  351. // This is subtly different from widow.rect(), because window
  352. // size may be different from its backing store size. This
  353. // happens when the window has been resized and the client
  354. // has not yet attached a new backing store. In this case,
  355. // we want to try to blit the backing store at the same place
  356. // it was previously, and fill the rest of the window with its
  357. // background color.
  358. Gfx::IntRect backing_rect;
  359. backing_rect.set_size(window.backing_store_visible_size());
  360. switch (WindowManager::the().resize_direction_of_window(window)) {
  361. case ResizeDirection::None:
  362. case ResizeDirection::Right:
  363. case ResizeDirection::Down:
  364. case ResizeDirection::DownRight:
  365. backing_rect.set_location(window_rect.location());
  366. break;
  367. case ResizeDirection::Left:
  368. case ResizeDirection::Up:
  369. case ResizeDirection::UpLeft:
  370. backing_rect.set_right_without_resize(window_rect.right());
  371. backing_rect.set_bottom_without_resize(window_rect.bottom());
  372. break;
  373. case ResizeDirection::UpRight:
  374. backing_rect.set_left(window.rect().left());
  375. backing_rect.set_bottom_without_resize(window_rect.bottom());
  376. break;
  377. case ResizeDirection::DownLeft:
  378. backing_rect.set_right_without_resize(window_rect.right());
  379. backing_rect.set_top(window_rect.top());
  380. break;
  381. default:
  382. VERIFY_NOT_REACHED();
  383. break;
  384. }
  385. Gfx::IntRect dirty_rect_in_backing_coordinates = update_window_rect.intersected(backing_rect)
  386. .translated(-backing_rect.location());
  387. if (!dirty_rect_in_backing_coordinates.is_empty()) {
  388. auto dst = backing_rect.location().translated(dirty_rect_in_backing_coordinates.location());
  389. if (window.client() && window.client()->is_unresponsive()) {
  390. if (window.is_opaque()) {
  391. painter.blit_filtered(dst, *backing_store, dirty_rect_in_backing_coordinates, [](Color src) {
  392. return src.to_grayscale().darkened(0.75f);
  393. });
  394. } else {
  395. u8 alpha = 255 * window.opacity();
  396. painter.blit_filtered(dst, *backing_store, dirty_rect_in_backing_coordinates, [&](Color src) {
  397. auto color = src.to_grayscale().darkened(0.75f);
  398. color.set_alpha(alpha);
  399. return color;
  400. });
  401. }
  402. } else {
  403. painter.blit(dst, *backing_store, dirty_rect_in_backing_coordinates, window.opacity());
  404. }
  405. }
  406. for (auto background_rect : update_window_rect.shatter(backing_rect))
  407. clear_window_rect(background_rect);
  408. };
  409. auto& dirty_rects = window.dirty_rects();
  410. if constexpr (COMPOSE_DEBUG) {
  411. for (auto& dirty_rect : dirty_rects.rects())
  412. dbgln(" dirty: {}", dirty_rect);
  413. for (auto& r : window.opaque_rects().rects())
  414. dbgln(" opaque: {}", r);
  415. for (auto& r : window.transparency_rects().rects())
  416. dbgln(" transparent: {}", r);
  417. }
  418. // Render opaque portions directly to the back buffer
  419. auto& opaque_rects = window.opaque_rects();
  420. if (!opaque_rects.is_empty()) {
  421. opaque_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
  422. for (auto* screen : window.screens()) {
  423. auto screen_render_rect = render_rect.intersected(screen->rect());
  424. if (screen_render_rect.is_empty())
  425. continue;
  426. dbgln_if(COMPOSE_DEBUG, " render opaque: {} on screen #{}", screen_render_rect, screen->index());
  427. prepare_rect(*screen, screen_render_rect);
  428. auto& back_painter = *screen->compositor_screen_data().m_back_painter;
  429. Gfx::PainterStateSaver saver(back_painter);
  430. back_painter.add_clip_rect(screen_render_rect);
  431. compose_window_rect(*screen, back_painter, screen_render_rect);
  432. }
  433. return IterationDecision::Continue;
  434. });
  435. }
  436. // Render the wallpaper for any transparency directly covering
  437. // the wallpaper
  438. auto& transparency_wallpaper_rects = window.transparency_wallpaper_rects();
  439. if (!transparency_wallpaper_rects.is_empty()) {
  440. transparency_wallpaper_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
  441. for (auto* screen : window.screens()) {
  442. auto screen_rect = screen->rect();
  443. auto screen_render_rect = render_rect.intersected(screen_rect);
  444. if (screen_render_rect.is_empty())
  445. continue;
  446. dbgln_if(COMPOSE_DEBUG, " render wallpaper: {} on screen #{}", screen_render_rect, screen->index());
  447. auto& temp_painter = *screen->compositor_screen_data().m_temp_painter;
  448. prepare_transparency_rect(*screen, screen_render_rect);
  449. paint_wallpaper(*screen, temp_painter, screen_render_rect, screen_rect);
  450. }
  451. return IterationDecision::Continue;
  452. });
  453. }
  454. auto& transparency_rects = window.transparency_rects();
  455. if (!transparency_rects.is_empty()) {
  456. transparency_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
  457. for (auto* screen : window.screens()) {
  458. auto screen_rect = screen->rect();
  459. auto screen_render_rect = render_rect.intersected(screen_rect);
  460. if (screen_render_rect.is_empty())
  461. continue;
  462. dbgln_if(COMPOSE_DEBUG, " render transparent: {} on screen #{}", screen_render_rect, screen->index());
  463. prepare_transparency_rect(*screen, screen_render_rect);
  464. auto& temp_painter = *screen->compositor_screen_data().m_temp_painter;
  465. Gfx::PainterStateSaver saver(temp_painter);
  466. temp_painter.add_clip_rect(screen_render_rect);
  467. compose_window_rect(*screen, temp_painter, screen_render_rect);
  468. }
  469. return IterationDecision::Continue;
  470. });
  471. }
  472. return IterationDecision::Continue;
  473. };
  474. // Paint the window stack.
  475. if (m_invalidated_window) {
  476. auto* fullscreen_window = wm.active_fullscreen_window();
  477. // FIXME: Remove the !WindowSwitcher::the().is_visible() check when WindowSwitcher is an overlay
  478. if (fullscreen_window && fullscreen_window->is_opaque() && !WindowSwitcher::the().is_visible()) {
  479. compose_window(*fullscreen_window);
  480. fullscreen_window->clear_dirty_rects();
  481. } else {
  482. wm.for_each_visible_window_from_back_to_front([&](Window& window) {
  483. compose_window(window);
  484. window.clear_dirty_rects();
  485. return IterationDecision::Continue;
  486. });
  487. }
  488. // Check that there are no overlapping transparent and opaque flush rectangles
  489. VERIFY(![&]() {
  490. bool is_overlapping = false;
  491. Screen::for_each([&](auto& screen) {
  492. auto& screen_data = screen.compositor_screen_data();
  493. auto& flush_transparent_rects = screen_data.m_flush_transparent_rects;
  494. auto& flush_rects = screen_data.m_flush_rects;
  495. for (auto& rect_transparent : flush_transparent_rects.rects()) {
  496. for (auto& rect_opaque : flush_rects.rects()) {
  497. if (rect_opaque.intersects(rect_transparent)) {
  498. dbgln("Transparent rect {} overlaps opaque rect: {}: {}", rect_transparent, rect_opaque, rect_opaque.intersected(rect_transparent));
  499. is_overlapping = true;
  500. return IterationDecision::Break;
  501. }
  502. }
  503. }
  504. return IterationDecision::Continue;
  505. });
  506. return is_overlapping;
  507. }());
  508. if (!m_overlay_list.is_empty()) {
  509. // Render everything to the temporary buffer before we copy it back
  510. render_overlays();
  511. }
  512. // Copy anything rendered to the temporary buffer to the back buffer
  513. Screen::for_each([&](auto& screen) {
  514. auto screen_rect = screen.rect();
  515. auto& screen_data = screen.compositor_screen_data();
  516. for (auto& rect : screen_data.m_flush_transparent_rects.rects())
  517. screen_data.m_back_painter->blit(rect.location(), *screen_data.m_temp_bitmap, rect.translated(-screen_rect.location()));
  518. return IterationDecision::Continue;
  519. });
  520. }
  521. m_invalidated_any = false;
  522. m_invalidated_window = false;
  523. m_invalidated_cursor = false;
  524. if (!m_animations.is_empty()) {
  525. Screen::for_each([&](auto& screen) {
  526. auto& screen_data = screen.compositor_screen_data();
  527. update_animations(screen, screen_data.m_flush_special_rects);
  528. if (!screen_data.m_flush_special_rects.is_empty())
  529. screen_data.m_have_flush_rects = true;
  530. return IterationDecision::Continue;
  531. });
  532. // As long as animations are running make sure we keep rendering frames
  533. m_invalidated_any = true;
  534. start_compose_async_timer();
  535. }
  536. if (need_to_draw_cursor) {
  537. auto& screen_data = cursor_screen.compositor_screen_data();
  538. screen_data.draw_cursor(cursor_screen, cursor_rect);
  539. }
  540. Screen::for_each([&](auto& screen) {
  541. flush(screen);
  542. return IterationDecision::Continue;
  543. });
  544. }
  545. void Compositor::flush(Screen& screen)
  546. {
  547. auto& screen_data = screen.compositor_screen_data();
  548. bool device_can_flush_buffers = screen.can_device_flush_buffers();
  549. if (!screen_data.m_have_flush_rects && (!screen_data.m_screen_can_set_buffer || screen_data.m_has_flipped)) {
  550. dbgln_if(COMPOSE_DEBUG, "Nothing to flush on screen #{} {}", screen.index(), screen_data.m_have_flush_rects);
  551. return;
  552. }
  553. screen_data.m_have_flush_rects = false;
  554. auto screen_rect = screen.rect();
  555. if (m_flash_flush) {
  556. Gfx::IntRect bounding_flash;
  557. for (auto& rect : screen_data.m_flush_rects.rects()) {
  558. screen_data.m_front_painter->fill_rect(rect, Color::Yellow);
  559. bounding_flash = bounding_flash.united(rect);
  560. }
  561. for (auto& rect : screen_data.m_flush_transparent_rects.rects()) {
  562. screen_data.m_front_painter->fill_rect(rect, Color::Green);
  563. bounding_flash = bounding_flash.united(rect);
  564. }
  565. if (!bounding_flash.is_empty()) {
  566. if (screen.can_device_flush_entire_buffer()) {
  567. screen.flush_display_entire_framebuffer();
  568. } else if (device_can_flush_buffers) {
  569. // If the device needs a flush we need to let it know that we
  570. // modified the front buffer!
  571. bounding_flash.translate_by(-screen_rect.location());
  572. screen.flush_display_front_buffer((!screen_data.m_screen_can_set_buffer || !screen_data.m_buffers_are_flipped) ? 0 : 1, bounding_flash);
  573. }
  574. usleep(10000);
  575. }
  576. }
  577. if (device_can_flush_buffers && screen_data.m_screen_can_set_buffer) {
  578. if (!screen_data.m_has_flipped) {
  579. // If we have not flipped any buffers before, we should be flushing
  580. // the entire buffer to make sure that the device has all the bits we wrote
  581. screen_data.m_flush_rects = { screen.rect() };
  582. }
  583. // If we also support buffer flipping we need to make sure we transfer all
  584. // updated areas to the device before we flip. We already modified the framebuffer
  585. // memory, but the device needs to know what areas we actually did update.
  586. for (auto& rect : screen_data.m_flush_rects.rects())
  587. screen.queue_flush_display_rect(rect.translated(-screen_rect.location()));
  588. for (auto& rect : screen_data.m_flush_transparent_rects.rects())
  589. screen.queue_flush_display_rect(rect.translated(-screen_rect.location()));
  590. for (auto& rect : screen_data.m_flush_special_rects.rects())
  591. screen.queue_flush_display_rect(rect.translated(-screen_rect.location()));
  592. screen.flush_display((!screen_data.m_screen_can_set_buffer || screen_data.m_buffers_are_flipped) ? 0 : 1);
  593. }
  594. if (screen_data.m_screen_can_set_buffer) {
  595. screen_data.flip_buffers(screen);
  596. screen_data.m_has_flipped = true;
  597. }
  598. auto do_flush = [&](Gfx::IntRect rect) {
  599. VERIFY(screen_rect.contains(rect));
  600. rect.translate_by(-screen_rect.location());
  601. // Almost everything in Compositor is in logical coordinates, with the painters having
  602. // a scale applied. But this routine accesses the backbuffer pixels directly, so it
  603. // must work in physical coordinates.
  604. auto scaled_rect = rect * screen.scale_factor();
  605. Gfx::ARGB32* front_ptr = screen_data.m_front_bitmap->scanline(scaled_rect.y()) + scaled_rect.x();
  606. Gfx::ARGB32* back_ptr = screen_data.m_back_bitmap->scanline(scaled_rect.y()) + scaled_rect.x();
  607. size_t pitch = screen_data.m_back_bitmap->pitch();
  608. // NOTE: The meaning of a flush depends on whether we can flip buffers or not.
  609. //
  610. // If flipping is supported, flushing means that we've flipped, and now we
  611. // copy the changed bits from the front buffer to the back buffer, to keep
  612. // them in sync.
  613. //
  614. // If flipping is not supported, flushing means that we copy the changed
  615. // rects from the backing bitmap to the display framebuffer.
  616. Gfx::ARGB32* to_ptr;
  617. const Gfx::ARGB32* from_ptr;
  618. if (screen_data.m_screen_can_set_buffer) {
  619. to_ptr = back_ptr;
  620. from_ptr = front_ptr;
  621. } else {
  622. to_ptr = front_ptr;
  623. from_ptr = back_ptr;
  624. }
  625. for (int y = 0; y < scaled_rect.height(); ++y) {
  626. fast_u32_copy(to_ptr, from_ptr, scaled_rect.width());
  627. from_ptr = (const Gfx::ARGB32*)((const u8*)from_ptr + pitch);
  628. to_ptr = (Gfx::ARGB32*)((u8*)to_ptr + pitch);
  629. }
  630. if (device_can_flush_buffers) {
  631. // Whether or not we need to flush buffers, we need to at least track what we modified
  632. // so that we can flush these areas next time before we flip buffers. Or, if we don't
  633. // support buffer flipping then we will flush them shortly.
  634. screen.queue_flush_display_rect(rect);
  635. }
  636. };
  637. for (auto& rect : screen_data.m_flush_rects.rects())
  638. do_flush(rect);
  639. for (auto& rect : screen_data.m_flush_transparent_rects.rects())
  640. do_flush(rect);
  641. for (auto& rect : screen_data.m_flush_special_rects.rects())
  642. do_flush(rect);
  643. if (device_can_flush_buffers && !screen_data.m_screen_can_set_buffer) {
  644. // If we also support flipping buffers we don't really need to flush these areas right now.
  645. // Instead, we skip this step and just keep track of them until shortly before the next flip.
  646. // If we however don't support flipping buffers then we need to flush the changed areas right
  647. // now so that they can be sent to the device.
  648. screen.flush_display(screen_data.m_buffers_are_flipped ? 1 : 0);
  649. }
  650. }
  651. void Compositor::invalidate_screen()
  652. {
  653. invalidate_screen(Screen::bounding_rect());
  654. }
  655. void Compositor::invalidate_screen(Gfx::IntRect const& screen_rect)
  656. {
  657. m_dirty_screen_rects.add(screen_rect.intersected(Screen::bounding_rect()));
  658. if (m_invalidated_any)
  659. return;
  660. m_invalidated_any = true;
  661. m_invalidated_window = true;
  662. start_compose_async_timer();
  663. }
  664. void Compositor::invalidate_screen(Gfx::DisjointIntRectSet const& rects)
  665. {
  666. m_dirty_screen_rects.add(rects.intersected(Screen::bounding_rect()));
  667. if (m_invalidated_any)
  668. return;
  669. m_invalidated_any = true;
  670. m_invalidated_window = true;
  671. start_compose_async_timer();
  672. }
  673. void Compositor::invalidate_window()
  674. {
  675. if (m_invalidated_window)
  676. return;
  677. m_invalidated_window = true;
  678. m_invalidated_any = true;
  679. start_compose_async_timer();
  680. }
  681. void Compositor::start_compose_async_timer()
  682. {
  683. // We delay composition by a timer interval, but to not affect latency too
  684. // much, if a pending compose is not already scheduled, we also schedule an
  685. // immediate compose the next spin of the event loop.
  686. if (!m_compose_timer->is_active()) {
  687. m_compose_timer->start();
  688. m_immediate_compose_timer->start();
  689. }
  690. }
  691. bool Compositor::set_background_color(DeprecatedString const& background_color)
  692. {
  693. auto color = Color::from_string(background_color);
  694. if (!color.has_value())
  695. return false;
  696. m_custom_background_color = color;
  697. g_config->write_entry("Background", "Color", background_color);
  698. bool succeeded = !g_config->sync().is_error();
  699. if (succeeded) {
  700. update_wallpaper_bitmap();
  701. Compositor::invalidate_screen();
  702. }
  703. return succeeded;
  704. }
  705. bool Compositor::set_wallpaper_mode(DeprecatedString const& mode)
  706. {
  707. g_config->write_entry("Background", "Mode", mode);
  708. bool succeeded = !g_config->sync().is_error();
  709. if (succeeded) {
  710. m_wallpaper_mode = mode_to_enum(mode);
  711. update_wallpaper_bitmap();
  712. Compositor::invalidate_screen();
  713. }
  714. return succeeded;
  715. }
  716. bool Compositor::set_wallpaper(RefPtr<Gfx::Bitmap const> bitmap)
  717. {
  718. if (!bitmap)
  719. m_wallpaper = nullptr;
  720. else
  721. m_wallpaper = bitmap;
  722. update_wallpaper_bitmap();
  723. invalidate_screen();
  724. return true;
  725. }
  726. void Compositor::update_wallpaper_bitmap()
  727. {
  728. Screen::for_each([&](Screen& screen) {
  729. auto& screen_data = screen.compositor_screen_data();
  730. if (m_wallpaper_mode != WallpaperMode::Stretch || !m_wallpaper) {
  731. screen_data.clear_wallpaper_bitmap();
  732. return IterationDecision::Continue;
  733. }
  734. // See if there is another screen with the same resolution and scale.
  735. // If so, we can use the same bitmap.
  736. bool share_bitmap_with_other_screen = false;
  737. Screen::for_each([&](Screen& screen2) {
  738. if (&screen == &screen2) {
  739. // Stop iterating here, we haven't updated wallpaper bitmaps for
  740. // this screen and the following screens.
  741. return IterationDecision::Break;
  742. }
  743. if (screen.size() == screen2.size() && screen.scale_factor() == screen2.scale_factor()) {
  744. auto& screen2_data = screen2.compositor_screen_data();
  745. // Use the same bitmap as the other screen
  746. screen_data.m_wallpaper_bitmap = screen2_data.m_wallpaper_bitmap;
  747. share_bitmap_with_other_screen = true;
  748. return IterationDecision::Break;
  749. }
  750. return IterationDecision::Continue;
  751. });
  752. if (share_bitmap_with_other_screen)
  753. return IterationDecision::Continue;
  754. if (screen.size() == m_wallpaper->size() && screen.scale_factor() == m_wallpaper->scale()) {
  755. // If the screen size is equal to the wallpaper size, we don't actually need to scale it
  756. screen_data.m_wallpaper_bitmap = m_wallpaper;
  757. } else {
  758. auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, screen.size(), screen.scale_factor()).release_value_but_fixme_should_propagate_errors();
  759. Gfx::Painter painter(*bitmap);
  760. painter.draw_scaled_bitmap(bitmap->rect(), *m_wallpaper, m_wallpaper->rect(), 1.f, Gfx::Painter::ScalingMode::BilinearBlend);
  761. screen_data.m_wallpaper_bitmap = move(bitmap);
  762. }
  763. return IterationDecision::Continue;
  764. });
  765. }
  766. void CompositorScreenData::clear_wallpaper_bitmap()
  767. {
  768. m_wallpaper_bitmap = nullptr;
  769. }
  770. void CompositorScreenData::flip_buffers(Screen& screen)
  771. {
  772. VERIFY(m_screen_can_set_buffer);
  773. swap(m_front_bitmap, m_back_bitmap);
  774. swap(m_front_painter, m_back_painter);
  775. screen.set_buffer(m_buffers_are_flipped ? 0 : 1);
  776. m_buffers_are_flipped = !m_buffers_are_flipped;
  777. }
  778. void Compositor::screen_resolution_changed()
  779. {
  780. // Screens may be gone now, invalidate any references to them
  781. m_current_cursor_screen = nullptr;
  782. init_bitmaps();
  783. invalidate_occlusions();
  784. overlay_rects_changed();
  785. update_wallpaper_bitmap();
  786. compose();
  787. }
  788. Gfx::IntRect Compositor::current_cursor_rect() const
  789. {
  790. auto& wm = WindowManager::the();
  791. auto& current_cursor = m_current_cursor ? *m_current_cursor : wm.active_cursor();
  792. Gfx::IntRect cursor_rect { ScreenInput::the().cursor_location().translated(-current_cursor.params().hotspot()), current_cursor.size() };
  793. if (wm.is_cursor_highlight_enabled()) {
  794. auto highlight_diameter = wm.cursor_highlight_radius() * 2;
  795. auto inflate_w = highlight_diameter - cursor_rect.width();
  796. auto inflate_h = highlight_diameter - cursor_rect.height();
  797. cursor_rect.inflate(inflate_w, inflate_h);
  798. // Ensures cursor stays in the same location when highlighting is enabled.
  799. cursor_rect.translate_by(-(inflate_w % 2), -(inflate_h % 2));
  800. }
  801. return cursor_rect;
  802. }
  803. void Compositor::invalidate_cursor(bool compose_immediately)
  804. {
  805. if (m_invalidated_cursor && !compose_immediately)
  806. return;
  807. m_invalidated_cursor = true;
  808. m_invalidated_any = true;
  809. if (compose_immediately)
  810. compose();
  811. else
  812. start_compose_async_timer();
  813. }
  814. void Compositor::change_cursor(Cursor const* cursor)
  815. {
  816. if (m_current_cursor == cursor)
  817. return;
  818. m_current_cursor = cursor;
  819. m_current_cursor_frame = 0;
  820. if (m_cursor_timer) {
  821. m_cursor_timer->stop();
  822. m_cursor_timer = nullptr;
  823. }
  824. if (cursor && cursor->params().frames() > 1 && cursor->params().frame_ms() != 0) {
  825. m_cursor_timer = add<Core::Timer>(
  826. cursor->params().frame_ms(), [this, cursor] {
  827. if (m_current_cursor != cursor)
  828. return;
  829. auto frames = cursor->params().frames();
  830. if (++m_current_cursor_frame >= frames)
  831. m_current_cursor_frame = 0;
  832. invalidate_cursor(true);
  833. });
  834. m_cursor_timer->start();
  835. }
  836. }
  837. void Compositor::render_overlays()
  838. {
  839. // NOTE: overlays should always be rendered to the temporary buffer!
  840. for (auto& overlay : m_overlay_list) {
  841. for (auto* screen : overlay.m_screens) {
  842. auto& screen_data = screen->compositor_screen_data();
  843. auto& painter = screen_data.overlay_painter();
  844. auto render_overlay_rect = [&](auto& intersected_overlay_rect) {
  845. Gfx::PainterStateSaver saver(painter);
  846. painter.add_clip_rect(intersected_overlay_rect);
  847. painter.translate(overlay.m_current_rect.location());
  848. overlay.render(painter, *screen);
  849. return IterationDecision::Continue;
  850. };
  851. auto const& render_rect = overlay.current_render_rect();
  852. screen_data.for_each_intersected_flushing_rect(render_rect, render_overlay_rect);
  853. // Now render any areas that are not somehow underneath any window or transparency area
  854. m_transparent_wallpaper_rects.for_each_intersected(render_rect, render_overlay_rect);
  855. }
  856. }
  857. }
  858. void Compositor::add_overlay(Overlay& overlay)
  859. {
  860. VERIFY(!overlay.m_list_node.is_in_list());
  861. auto zorder = overlay.zorder();
  862. bool did_insert = false;
  863. for (auto& other_overlay : m_overlay_list) {
  864. if (other_overlay.zorder() > zorder) {
  865. m_overlay_list.insert_before(other_overlay, overlay);
  866. did_insert = true;
  867. break;
  868. }
  869. }
  870. if (!did_insert)
  871. m_overlay_list.append(overlay);
  872. overlay.invalidate();
  873. overlay_rects_changed();
  874. }
  875. void Compositor::remove_overlay(Overlay& overlay)
  876. {
  877. m_overlay_list.remove(overlay);
  878. auto last_rendered_rect = overlay.current_render_rect();
  879. if (!last_rendered_rect.is_empty()) {
  880. // We need to invalidate the entire area. While recomputing occlusions
  881. // will detect areas no longer occupied by overlays, if there are other
  882. // overlays intersecting with the overlay that was removed, then that
  883. // area would not get re-rendered.
  884. invalidate_screen(last_rendered_rect);
  885. }
  886. overlay_rects_changed();
  887. }
  888. void CompositorScreenData::draw_cursor(Screen& screen, Gfx::IntRect const& cursor_rect)
  889. {
  890. auto& wm = WindowManager::the();
  891. if (!m_cursor_back_bitmap || m_cursor_back_bitmap->size() != cursor_rect.size() || m_cursor_back_bitmap->scale() != screen.scale_factor()) {
  892. m_cursor_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, cursor_rect.size(), screen.scale_factor()).release_value_but_fixme_should_propagate_errors();
  893. m_cursor_back_painter = make<Gfx::Painter>(*m_cursor_back_bitmap);
  894. }
  895. auto& compositor = Compositor::the();
  896. auto& current_cursor = compositor.m_current_cursor ? *compositor.m_current_cursor : wm.active_cursor();
  897. auto screen_rect = screen.rect();
  898. m_cursor_back_painter->blit({ 0, 0 }, *m_back_bitmap, cursor_rect.intersected(screen_rect).translated(-screen_rect.location()));
  899. auto cursor_src_rect = current_cursor.source_rect(compositor.m_current_cursor_frame);
  900. auto cursor_blit_pos = current_cursor.rect().centered_within(cursor_rect).location();
  901. if (wm.is_cursor_highlight_enabled()) {
  902. Gfx::AntiAliasingPainter aa_back_painter { *m_back_painter };
  903. aa_back_painter.fill_ellipse(cursor_rect, wm.cursor_highlight_color());
  904. }
  905. m_back_painter->blit(cursor_blit_pos, current_cursor.bitmap(screen.scale_factor()), cursor_src_rect);
  906. m_flush_special_rects.add(Gfx::IntRect(cursor_rect.location(), cursor_rect.size()).intersected(screen.rect()));
  907. m_have_flush_rects = true;
  908. m_last_cursor_rect = cursor_rect;
  909. VERIFY(compositor.m_current_cursor_screen == &screen);
  910. m_cursor_back_is_valid = true;
  911. }
  912. bool CompositorScreenData::restore_cursor_back(Screen& screen, Gfx::IntRect& last_cursor_rect)
  913. {
  914. if (!m_cursor_back_is_valid || !m_cursor_back_bitmap || m_cursor_back_bitmap->scale() != m_back_bitmap->scale())
  915. return false;
  916. last_cursor_rect = m_last_cursor_rect.intersected(screen.rect());
  917. m_back_painter->blit(last_cursor_rect.location(), *m_cursor_back_bitmap, { { 0, 0 }, last_cursor_rect.size() });
  918. m_flush_special_rects.add(last_cursor_rect.intersected(screen.rect()));
  919. m_have_flush_rects = true;
  920. m_cursor_back_is_valid = false;
  921. return true;
  922. }
  923. void Compositor::update_fonts()
  924. {
  925. ScreenNumberOverlay::pick_font();
  926. }
  927. void Compositor::notify_display_links()
  928. {
  929. ConnectionFromClient::for_each_client([](auto& client) {
  930. client.notify_display_link({});
  931. });
  932. }
  933. void Compositor::increment_display_link_count(Badge<ConnectionFromClient>)
  934. {
  935. ++m_display_link_count;
  936. if (m_display_link_count == 1)
  937. m_display_link_notify_timer->start();
  938. }
  939. void Compositor::decrement_display_link_count(Badge<ConnectionFromClient>)
  940. {
  941. VERIFY(m_display_link_count);
  942. --m_display_link_count;
  943. if (!m_display_link_count)
  944. m_display_link_notify_timer->stop();
  945. }
  946. void Compositor::invalidate_current_screen_number_rects()
  947. {
  948. Screen::for_each([&](auto& screen) {
  949. auto& screen_data = screen.compositor_screen_data();
  950. if (screen_data.m_screen_number_overlay)
  951. screen_data.m_screen_number_overlay->invalidate();
  952. return IterationDecision::Continue;
  953. });
  954. }
  955. void Compositor::increment_show_screen_number(Badge<ConnectionFromClient>)
  956. {
  957. if (m_show_screen_number_count++ == 0) {
  958. Screen::for_each([&](auto& screen) {
  959. auto& screen_data = screen.compositor_screen_data();
  960. VERIFY(!screen_data.m_screen_number_overlay);
  961. screen_data.m_screen_number_overlay = create_overlay<ScreenNumberOverlay>(screen);
  962. screen_data.m_screen_number_overlay->set_enabled(true);
  963. return IterationDecision::Continue;
  964. });
  965. }
  966. }
  967. void Compositor::decrement_show_screen_number(Badge<ConnectionFromClient>)
  968. {
  969. if (--m_show_screen_number_count == 0) {
  970. invalidate_current_screen_number_rects();
  971. Screen::for_each([&](auto& screen) {
  972. screen.compositor_screen_data().m_screen_number_overlay = nullptr;
  973. return IterationDecision::Continue;
  974. });
  975. }
  976. }
  977. void Compositor::overlays_theme_changed()
  978. {
  979. for (auto& overlay : m_overlay_list)
  980. overlay.theme_changed();
  981. overlay_rects_changed();
  982. }
  983. void Compositor::overlay_rects_changed()
  984. {
  985. if (m_overlay_rects_changed)
  986. return;
  987. m_overlay_rects_changed = true;
  988. m_invalidated_any = true;
  989. invalidate_occlusions();
  990. start_compose_async_timer();
  991. }
  992. void Compositor::recompute_overlay_rects()
  993. {
  994. // The purpose of this is to gather all areas that we will render over
  995. // regular window contents. This effectively just forces those areas to
  996. // be rendered as transparency areas, which allows us to render these
  997. // flicker-free.
  998. swap(m_last_rendered_overlay_rects, m_overlay_rects);
  999. m_overlay_rects.clear_with_capacity();
  1000. for (auto& overlay : m_overlay_list) {
  1001. auto& render_rect = overlay.rect();
  1002. m_overlay_rects.add(render_rect);
  1003. // Invalidate areas that are no longer in the rendered area because the overlay was moved.
  1004. auto previous_rects = overlay.current_render_rect().shatter(render_rect);
  1005. for (auto& rect : previous_rects)
  1006. invalidate_screen(rect);
  1007. // Save the rectangle we are using for rendering from now on
  1008. bool needs_invalidation = overlay.apply_render_rect();
  1009. // Cache which screens this overlay are rendered on
  1010. overlay.m_screens.clear_with_capacity();
  1011. Screen::for_each([&](auto& screen) {
  1012. if (render_rect.intersects(screen.rect()))
  1013. overlay.m_screens.append(&screen);
  1014. return IterationDecision::Continue;
  1015. });
  1016. if (needs_invalidation)
  1017. invalidate_screen(render_rect);
  1018. }
  1019. // Invalidate rects that are not going to get rendered anymore, e.g.
  1020. // because overlays were removed or rectangles were changed
  1021. auto no_longer_rendered_rects = m_last_rendered_overlay_rects.shatter(m_overlay_rects);
  1022. for (auto& rect : no_longer_rendered_rects.rects())
  1023. invalidate_screen(rect);
  1024. }
  1025. void Compositor::recompute_occlusions()
  1026. {
  1027. auto& wm = WindowManager::the();
  1028. bool is_switcher_visible = wm.m_switcher->is_visible();
  1029. auto never_occlude = [&](WindowStack& window_stack) {
  1030. if (is_switcher_visible) {
  1031. switch (wm.m_switcher->mode()) {
  1032. case WindowSwitcher::Mode::ShowCurrentDesktop:
  1033. // Any window on the currently rendered desktop should not be occluded, even if it's behind
  1034. // another window entirely.
  1035. return &window_stack == m_current_window_stack || &window_stack == m_transitioning_to_window_stack;
  1036. case WindowSwitcher::Mode::ShowAllWindows:
  1037. // The window switcher wants to know about all windows, even those on other desktops
  1038. return true;
  1039. }
  1040. }
  1041. return false;
  1042. };
  1043. wm.for_each_window_stack([&](WindowStack& window_stack) {
  1044. if (&window_stack == m_current_window_stack || &window_stack == m_transitioning_to_window_stack) {
  1045. // We'll calculate precise occlusions for these further down. Changing occlusions right now
  1046. // may trigger an additional unnecessary notification
  1047. } else {
  1048. window_stack.set_all_occluded(!never_occlude(window_stack));
  1049. }
  1050. return IterationDecision::Continue;
  1051. });
  1052. if (m_overlay_rects_changed) {
  1053. m_overlay_rects_changed = false;
  1054. recompute_overlay_rects();
  1055. }
  1056. if constexpr (OCCLUSIONS_DEBUG) {
  1057. dbgln("OCCLUSIONS:");
  1058. for (auto& rect : m_overlay_rects.rects())
  1059. dbgln(" overlay: {}", rect);
  1060. }
  1061. bool window_stack_transition_in_progress = m_transitioning_to_window_stack != nullptr;
  1062. auto& main_screen = Screen::main();
  1063. auto* fullscreen_window = wm.active_fullscreen_window();
  1064. // FIXME: Remove the !WindowSwitcher::the().is_visible() check when WindowSwitcher is an overlay
  1065. if (fullscreen_window && !WindowSwitcher::the().is_visible()) {
  1066. // TODO: support fullscreen windows on all screens
  1067. auto screen_rect = main_screen.rect();
  1068. wm.for_each_visible_window_from_front_to_back([&](Window& w) {
  1069. auto& visible_opaque = w.opaque_rects();
  1070. auto& transparency_rects = w.transparency_rects();
  1071. auto& transparency_wallpaper_rects = w.transparency_wallpaper_rects();
  1072. w.affected_transparency_rects().clear();
  1073. w.screens().clear_with_capacity();
  1074. if (&w == fullscreen_window) {
  1075. w.screens().append(&main_screen);
  1076. if (w.is_opaque()) {
  1077. visible_opaque = screen_rect;
  1078. transparency_rects.clear();
  1079. transparency_wallpaper_rects.clear();
  1080. } else {
  1081. visible_opaque.clear();
  1082. transparency_rects = screen_rect;
  1083. transparency_wallpaper_rects = screen_rect;
  1084. }
  1085. } else {
  1086. visible_opaque.clear();
  1087. transparency_rects.clear();
  1088. transparency_wallpaper_rects.clear();
  1089. }
  1090. return IterationDecision::Continue;
  1091. });
  1092. m_opaque_wallpaper_rects.clear();
  1093. }
  1094. // FIXME: Remove the WindowSwitcher::the().is_visible() check when WindowSwitcher is an overlay
  1095. if (!fullscreen_window || WindowSwitcher::the().is_visible() || (fullscreen_window && !fullscreen_window->is_opaque())) {
  1096. Gfx::DisjointIntRectSet remaining_visible_screen_rects;
  1097. remaining_visible_screen_rects.add_many(Screen::rects());
  1098. bool have_transparent = false;
  1099. wm.for_each_visible_window_from_front_to_back([&](Window& w) {
  1100. VERIFY(!w.is_minimized());
  1101. w.transparency_wallpaper_rects().clear();
  1102. auto previous_visible_opaque = move(w.opaque_rects());
  1103. auto previous_visible_transparency = move(w.transparency_rects());
  1104. auto invalidate_previous_render_rects = [&](Gfx::IntRect const& new_render_rect) {
  1105. if (!previous_visible_opaque.is_empty()) {
  1106. if (new_render_rect.is_empty())
  1107. invalidate_screen(previous_visible_opaque);
  1108. else
  1109. invalidate_screen(previous_visible_opaque.shatter(new_render_rect));
  1110. }
  1111. if (!previous_visible_transparency.is_empty()) {
  1112. if (new_render_rect.is_empty())
  1113. invalidate_screen(previous_visible_transparency);
  1114. else
  1115. invalidate_screen(previous_visible_transparency.shatter(new_render_rect));
  1116. }
  1117. };
  1118. auto& visible_opaque = w.opaque_rects();
  1119. auto& transparency_rects = w.transparency_rects();
  1120. bool should_invalidate_old = w.should_invalidate_last_rendered_screen_rects();
  1121. auto& affected_transparency_rects = w.affected_transparency_rects();
  1122. affected_transparency_rects.clear();
  1123. w.screens().clear_with_capacity();
  1124. auto transition_offset = window_transition_offset(w);
  1125. auto transparent_frame_render_rects = w.frame().transparent_render_rects();
  1126. auto opaque_frame_render_rects = w.frame().opaque_render_rects();
  1127. if (window_stack_transition_in_progress) {
  1128. transparent_frame_render_rects.translate_by(transition_offset);
  1129. opaque_frame_render_rects.translate_by(transition_offset);
  1130. }
  1131. if (should_invalidate_old) {
  1132. for (auto& rect : opaque_frame_render_rects.rects())
  1133. invalidate_previous_render_rects(rect);
  1134. for (auto& rect : transparent_frame_render_rects.rects())
  1135. invalidate_previous_render_rects(rect);
  1136. }
  1137. if (auto transparent_render_rects = transparent_frame_render_rects.intersected(remaining_visible_screen_rects); !transparent_render_rects.is_empty())
  1138. transparency_rects = move(transparent_render_rects);
  1139. if (auto opaque_render_rects = opaque_frame_render_rects.intersected(remaining_visible_screen_rects); !opaque_render_rects.is_empty())
  1140. visible_opaque = move(opaque_render_rects);
  1141. auto render_rect_on_screen = w.frame().render_rect().translated(transition_offset);
  1142. auto visible_window_rects = remaining_visible_screen_rects.intersected(w.rect().translated(transition_offset));
  1143. Gfx::DisjointIntRectSet opaque_covering;
  1144. Gfx::DisjointIntRectSet transparent_covering;
  1145. bool found_this_window = false;
  1146. wm.for_each_visible_window_from_back_to_front([&](Window& w2) {
  1147. if (!found_this_window) {
  1148. if (&w == &w2)
  1149. found_this_window = true;
  1150. return IterationDecision::Continue;
  1151. }
  1152. VERIFY(!w2.is_minimized());
  1153. auto w2_render_rect = w2.frame().render_rect();
  1154. auto w2_render_rect_on_screen = w2_render_rect;
  1155. auto w2_transition_offset = window_transition_offset(w2);
  1156. if (window_stack_transition_in_progress)
  1157. w2_render_rect_on_screen.translate_by(w2_transition_offset);
  1158. if (!render_rect_on_screen.intersects(w2_render_rect_on_screen))
  1159. return IterationDecision::Continue;
  1160. auto opaque_rects = w2.frame().opaque_render_rects();
  1161. auto transparent_rects = w2.frame().transparent_render_rects();
  1162. if (window_stack_transition_in_progress) {
  1163. auto transition_offset_2 = window_transition_offset(w2);
  1164. opaque_rects.translate_by(transition_offset_2);
  1165. transparent_rects.translate_by(transition_offset_2);
  1166. }
  1167. opaque_rects = opaque_rects.intersected(render_rect_on_screen);
  1168. transparent_rects = transparent_rects.intersected(render_rect_on_screen);
  1169. if (opaque_rects.is_empty() && transparent_rects.is_empty())
  1170. return IterationDecision::Continue;
  1171. VERIFY(!opaque_rects.intersects(transparent_rects));
  1172. for (auto& covering : opaque_rects.rects()) {
  1173. opaque_covering.add(covering);
  1174. if (!visible_window_rects.is_empty())
  1175. visible_window_rects = visible_window_rects.shatter(covering);
  1176. if (!visible_opaque.is_empty()) {
  1177. auto uncovered_opaque = visible_opaque.shatter(covering);
  1178. visible_opaque = move(uncovered_opaque);
  1179. }
  1180. if (!transparency_rects.is_empty()) {
  1181. auto uncovered_transparency = transparency_rects.shatter(covering);
  1182. transparency_rects = move(uncovered_transparency);
  1183. }
  1184. if (!transparent_covering.is_empty()) {
  1185. auto uncovered_transparency = transparent_covering.shatter(covering);
  1186. transparent_covering = move(uncovered_transparency);
  1187. }
  1188. }
  1189. if (!transparent_rects.is_empty())
  1190. transparent_covering.add(transparent_rects.shatter(opaque_covering));
  1191. VERIFY(!transparent_covering.intersects(opaque_covering));
  1192. return IterationDecision::Continue;
  1193. });
  1194. VERIFY(opaque_covering.is_empty() || render_rect_on_screen.contains(opaque_covering.rects()));
  1195. if (!m_overlay_rects.is_empty() && m_overlay_rects.intersects(visible_opaque)) {
  1196. // In order to render overlays flicker-free we need to force this area into the
  1197. // temporary transparency rendering buffer
  1198. transparent_covering.add(m_overlay_rects.intersected(visible_opaque));
  1199. }
  1200. if (!transparent_covering.is_empty()) {
  1201. VERIFY(!transparent_covering.intersects(opaque_covering));
  1202. transparency_rects.add(transparent_covering);
  1203. if (!visible_opaque.is_empty()) {
  1204. auto uncovered_opaque = visible_opaque.shatter(transparent_covering);
  1205. visible_opaque = move(uncovered_opaque);
  1206. }
  1207. // Now that we know what transparency rectangles are immediately covering our window
  1208. // figure out what windows they belong to and add them to the affected transparency rects.
  1209. // We can't do the same with the windows below as we haven't gotten to those yet. These
  1210. // will be determined after we're done with this pass.
  1211. found_this_window = false;
  1212. wm.for_each_visible_window_from_back_to_front([&](Window& w2) {
  1213. if (!found_this_window) {
  1214. if (&w == &w2)
  1215. found_this_window = true;
  1216. return IterationDecision::Continue;
  1217. }
  1218. auto affected_transparency = transparent_covering.intersected(w2.transparency_rects());
  1219. if (!affected_transparency.is_empty()) {
  1220. auto result = affected_transparency_rects.set(&w2, move(affected_transparency));
  1221. VERIFY(result == AK::HashSetResult::InsertedNewEntry);
  1222. }
  1223. return IterationDecision::Continue;
  1224. });
  1225. }
  1226. // This window should not be occluded while the window switcher is interested in it (depending
  1227. // on the mode it's in). If it isn't then determine occlusions based on whether the window
  1228. // rect has any visible areas at all.
  1229. w.set_occluded(never_occlude(w.window_stack()) ? false : visible_window_rects.is_empty());
  1230. bool have_opaque = !visible_opaque.is_empty();
  1231. if (!transparency_rects.is_empty())
  1232. have_transparent = true;
  1233. if (have_transparent || have_opaque) {
  1234. // Figure out what screens this window is rendered on
  1235. // We gather this information so we can more quickly
  1236. // render the window on each of the screens that it
  1237. // needs to be rendered on.
  1238. Screen::for_each([&](auto& screen) {
  1239. auto screen_rect = screen.rect();
  1240. for (auto& r : visible_opaque.rects()) {
  1241. if (r.intersects(screen_rect)) {
  1242. w.screens().append(&screen);
  1243. return IterationDecision::Continue;
  1244. }
  1245. }
  1246. for (auto& r : transparency_rects.rects()) {
  1247. if (r.intersects(screen_rect)) {
  1248. w.screens().append(&screen);
  1249. return IterationDecision::Continue;
  1250. }
  1251. }
  1252. return IterationDecision::Continue;
  1253. });
  1254. }
  1255. if (!visible_opaque.is_empty()) {
  1256. VERIFY(!visible_opaque.intersects(transparency_rects));
  1257. // Determine visible area for the window below
  1258. remaining_visible_screen_rects = remaining_visible_screen_rects.shatter(visible_opaque);
  1259. }
  1260. return IterationDecision::Continue;
  1261. });
  1262. if (have_transparent) {
  1263. // Also, now that we have completed the first pass we can determine the affected
  1264. // transparency rects below a given window
  1265. wm.for_each_visible_window_from_back_to_front([&](Window& w) {
  1266. // Any area left in remaining_visible_screen_rects will need to be rendered with the wallpaper first
  1267. auto& transparency_rects = w.transparency_rects();
  1268. auto& transparency_wallpaper_rects = w.transparency_wallpaper_rects();
  1269. if (transparency_rects.is_empty()) {
  1270. VERIFY(transparency_wallpaper_rects.is_empty()); // Should have been cleared in the first pass
  1271. } else {
  1272. transparency_wallpaper_rects = remaining_visible_screen_rects.intersected(transparency_rects);
  1273. if (!transparency_wallpaper_rects.is_empty()) {
  1274. auto remaining_visible = remaining_visible_screen_rects.shatter(transparency_wallpaper_rects);
  1275. remaining_visible_screen_rects = move(remaining_visible);
  1276. }
  1277. }
  1278. // Figure out the affected transparency rects underneath. First figure out if any transparency is visible at all
  1279. Gfx::DisjointIntRectSet transparent_underneath;
  1280. wm.for_each_visible_window_from_back_to_front([&](Window& w2) {
  1281. if (&w == &w2)
  1282. return IterationDecision::Break;
  1283. auto& opaque_rects2 = w2.opaque_rects();
  1284. if (!opaque_rects2.is_empty()) {
  1285. auto uncovered_transparency = transparent_underneath.shatter(opaque_rects2);
  1286. transparent_underneath = move(uncovered_transparency);
  1287. }
  1288. w2.transparency_rects().for_each_intersected(transparency_rects, [&](auto& rect) {
  1289. transparent_underneath.add(rect);
  1290. return IterationDecision::Continue;
  1291. });
  1292. return IterationDecision::Continue;
  1293. });
  1294. if (!transparent_underneath.is_empty()) {
  1295. // Now that we know there are some transparency rects underneath that are visible
  1296. // figure out what windows they belong to
  1297. auto& affected_transparency_rects = w.affected_transparency_rects();
  1298. wm.for_each_visible_window_from_back_to_front([&](Window& w2) {
  1299. if (&w == &w2)
  1300. return IterationDecision::Break;
  1301. auto& transparency_rects2 = w2.transparency_rects();
  1302. if (transparency_rects2.is_empty())
  1303. return IterationDecision::Continue;
  1304. auto affected_transparency = transparent_underneath.intersected(transparency_rects2);
  1305. if (!affected_transparency.is_empty()) {
  1306. auto result = affected_transparency_rects.set(&w2, move(affected_transparency));
  1307. VERIFY(result == AK::HashSetResult::InsertedNewEntry);
  1308. }
  1309. return IterationDecision::Continue;
  1310. });
  1311. }
  1312. return IterationDecision::Continue;
  1313. });
  1314. }
  1315. m_transparent_wallpaper_rects.clear_with_capacity();
  1316. if (!m_overlay_rects.is_empty() && m_overlay_rects.intersects(remaining_visible_screen_rects)) {
  1317. // Check if any overlay rects are remaining that are not somehow above any windows
  1318. m_transparent_wallpaper_rects = m_overlay_rects.intersected(remaining_visible_screen_rects);
  1319. auto remaining_visible_not_covered = remaining_visible_screen_rects.shatter(m_overlay_rects);
  1320. remaining_visible_screen_rects = move(remaining_visible_not_covered);
  1321. }
  1322. m_opaque_wallpaper_rects = move(remaining_visible_screen_rects);
  1323. }
  1324. if constexpr (OCCLUSIONS_DEBUG) {
  1325. for (auto& r : m_opaque_wallpaper_rects.rects())
  1326. dbgln(" wallpaper opaque: {}", r);
  1327. }
  1328. wm.for_each_visible_window_from_back_to_front([&](Window& w) {
  1329. auto window_frame_rect = w.frame().render_rect();
  1330. if (w.is_minimized() || window_frame_rect.is_empty() || w.screens().is_empty())
  1331. return IterationDecision::Continue;
  1332. if constexpr (OCCLUSIONS_DEBUG) {
  1333. dbgln(" Window {} frame rect: {} rendered on screens: {}", w.title(), window_frame_rect, w.screens().size());
  1334. for (auto& s : w.screens())
  1335. dbgln(" screen: #{}", s->index());
  1336. for (auto& r : w.opaque_rects().rects())
  1337. dbgln(" opaque: {}", r);
  1338. for (auto& r : w.transparency_wallpaper_rects().rects())
  1339. dbgln(" transparent wallpaper: {}", r);
  1340. for (auto& r : w.transparency_rects().rects())
  1341. dbgln(" transparent: {}", r);
  1342. for (auto& it : w.affected_transparency_rects()) {
  1343. dbgln(" affects {}:", it.key->title());
  1344. for (auto& r : it.value.rects())
  1345. dbgln(" transparent: {}", r);
  1346. }
  1347. }
  1348. VERIFY(!w.opaque_rects().intersects(m_opaque_wallpaper_rects));
  1349. VERIFY(!w.transparency_rects().intersects(m_opaque_wallpaper_rects));
  1350. VERIFY(!w.transparency_wallpaper_rects().intersects(m_opaque_wallpaper_rects));
  1351. return IterationDecision::Continue;
  1352. });
  1353. }
  1354. void Compositor::register_animation(Badge<Animation>, Animation& animation)
  1355. {
  1356. VERIFY(!m_animations_running);
  1357. bool was_empty = m_animations.is_empty();
  1358. auto result = m_animations.set(&animation);
  1359. VERIFY(result == AK::HashSetResult::InsertedNewEntry);
  1360. if (was_empty) {
  1361. m_invalidated_any = true;
  1362. start_compose_async_timer();
  1363. }
  1364. }
  1365. void Compositor::unregister_animation(Badge<Animation>, Animation& animation)
  1366. {
  1367. VERIFY(!m_animations_running);
  1368. bool was_removed = m_animations.remove(&animation);
  1369. VERIFY(was_removed);
  1370. }
  1371. void Compositor::update_animations(Screen& screen, Gfx::DisjointIntRectSet& flush_rects)
  1372. {
  1373. Vector<NonnullRefPtr<Animation>, 16> finished_animations;
  1374. ScopeGuard call_stop_handlers([&] {
  1375. for (auto& animation : finished_animations)
  1376. animation->call_stop_handler({});
  1377. });
  1378. TemporaryChange animations_running(m_animations_running, true);
  1379. auto& painter = *screen.compositor_screen_data().m_back_painter;
  1380. // Iterating over the animations using remove_all_matching we can iterate
  1381. // and immediately remove finished animations without having to keep track
  1382. // of them in a separate container.
  1383. m_animations.remove_all_matching([&](auto* animation) {
  1384. VERIFY(animation->is_running());
  1385. if (!animation->update(painter, screen, flush_rects)) {
  1386. // Mark it as removed so that the Animation::on_stop handler doesn't
  1387. // trigger the Animation object from being destroyed, causing it to
  1388. // unregister while we still loop over them.
  1389. animation->was_removed({});
  1390. finished_animations.append(*animation);
  1391. return true;
  1392. }
  1393. return false;
  1394. });
  1395. }
  1396. void Compositor::create_window_stack_switch_overlay(WindowStack& target_stack)
  1397. {
  1398. stop_window_stack_switch_overlay_timer();
  1399. Screen::for_each([&](auto& screen) {
  1400. auto& screen_data = screen.compositor_screen_data();
  1401. screen_data.m_window_stack_switch_overlay = nullptr; // delete it first
  1402. screen_data.m_window_stack_switch_overlay = create_overlay<WindowStackSwitchOverlay>(screen, target_stack);
  1403. screen_data.m_window_stack_switch_overlay->set_enabled(true);
  1404. return IterationDecision::Continue;
  1405. });
  1406. }
  1407. void Compositor::remove_window_stack_switch_overlays()
  1408. {
  1409. Screen::for_each([&](auto& screen) {
  1410. screen.compositor_screen_data().m_window_stack_switch_overlay = nullptr;
  1411. return IterationDecision::Continue;
  1412. });
  1413. }
  1414. void Compositor::stop_window_stack_switch_overlay_timer()
  1415. {
  1416. if (m_stack_switch_overlay_timer) {
  1417. // Cancel any timer, we're going to delete the overlay
  1418. m_stack_switch_overlay_timer->stop();
  1419. m_stack_switch_overlay_timer = nullptr;
  1420. }
  1421. }
  1422. void Compositor::start_window_stack_switch_overlay_timer()
  1423. {
  1424. if (m_stack_switch_overlay_timer) {
  1425. m_stack_switch_overlay_timer->stop();
  1426. m_stack_switch_overlay_timer = nullptr;
  1427. }
  1428. bool have_overlay = false;
  1429. Screen::for_each([&](auto& screen) {
  1430. if (screen.compositor_screen_data().m_window_stack_switch_overlay) {
  1431. have_overlay = true;
  1432. return IterationDecision::Break;
  1433. }
  1434. return IterationDecision::Continue;
  1435. });
  1436. if (!have_overlay)
  1437. return;
  1438. m_stack_switch_overlay_timer = Core::Timer::create_single_shot(
  1439. 500,
  1440. [this] {
  1441. remove_window_stack_switch_overlays();
  1442. },
  1443. this)
  1444. .release_value_but_fixme_should_propagate_errors();
  1445. m_stack_switch_overlay_timer->start();
  1446. }
  1447. void Compositor::finish_window_stack_switch()
  1448. {
  1449. VERIFY(m_transitioning_to_window_stack);
  1450. VERIFY(m_current_window_stack);
  1451. VERIFY(m_transitioning_to_window_stack != m_current_window_stack);
  1452. m_current_window_stack->set_transition_offset({}, {});
  1453. m_transitioning_to_window_stack->set_transition_offset({}, {});
  1454. auto* previous_window_stack = m_current_window_stack;
  1455. m_current_window_stack = m_transitioning_to_window_stack;
  1456. m_transitioning_to_window_stack = nullptr;
  1457. m_window_stack_transition_animation = nullptr;
  1458. auto& wm = WindowManager::the();
  1459. if (!wm.m_switcher->is_visible())
  1460. previous_window_stack->set_all_occluded(true);
  1461. wm.did_switch_window_stack({}, *previous_window_stack, *m_current_window_stack);
  1462. invalidate_occlusions();
  1463. // Rather than invalidating the entire we could invalidate all render rectangles
  1464. // that are affected by the transition offset before and after changing it.
  1465. invalidate_screen();
  1466. start_window_stack_switch_overlay_timer();
  1467. }
  1468. void Compositor::set_current_window_stack_no_transition(WindowStack& new_window_stack)
  1469. {
  1470. if (m_transitioning_to_window_stack) {
  1471. finish_window_stack_switch();
  1472. VERIFY(!m_window_stack_transition_animation);
  1473. VERIFY(!m_transitioning_to_window_stack);
  1474. }
  1475. if (m_current_window_stack == &new_window_stack)
  1476. return;
  1477. m_current_window_stack = &new_window_stack;
  1478. invalidate_for_window_stack_merge_or_change();
  1479. }
  1480. void Compositor::invalidate_for_window_stack_merge_or_change()
  1481. {
  1482. invalidate_occlusions();
  1483. invalidate_screen();
  1484. }
  1485. void Compositor::switch_to_window_stack(WindowStack& new_window_stack, bool show_overlay)
  1486. {
  1487. if (m_transitioning_to_window_stack) {
  1488. if (m_transitioning_to_window_stack == &new_window_stack)
  1489. return;
  1490. // A switch is in progress, but the user is impatient. Finish the transition instantly
  1491. finish_window_stack_switch();
  1492. VERIFY(!m_window_stack_transition_animation);
  1493. // Now switch to the next target as usual
  1494. }
  1495. VERIFY(m_current_window_stack);
  1496. if (&new_window_stack == m_current_window_stack) {
  1497. // So that the user knows which stack they're on, show the overlay briefly
  1498. if (show_overlay) {
  1499. create_window_stack_switch_overlay(*m_current_window_stack);
  1500. start_window_stack_switch_overlay_timer();
  1501. } else {
  1502. stop_window_stack_switch_overlay_timer();
  1503. remove_window_stack_switch_overlays();
  1504. }
  1505. return;
  1506. }
  1507. VERIFY(!m_transitioning_to_window_stack);
  1508. m_transitioning_to_window_stack = &new_window_stack;
  1509. auto window_stack_size = Screen::bounding_rect().size();
  1510. int delta_x = 0;
  1511. if (new_window_stack.column() < m_current_window_stack->column())
  1512. delta_x = window_stack_size.width();
  1513. else if (new_window_stack.column() > m_current_window_stack->column())
  1514. delta_x = -window_stack_size.width();
  1515. int delta_y = 0;
  1516. if (new_window_stack.row() < m_current_window_stack->row())
  1517. delta_y = window_stack_size.height();
  1518. else if (new_window_stack.row() > m_current_window_stack->row()) {
  1519. delta_y = -window_stack_size.height();
  1520. }
  1521. m_transitioning_to_window_stack->set_transition_offset({}, { -delta_x, -delta_y });
  1522. m_current_window_stack->set_transition_offset({}, {});
  1523. if (show_overlay) {
  1524. // We start the timer when the animation ends!
  1525. create_window_stack_switch_overlay(*m_transitioning_to_window_stack);
  1526. } else {
  1527. stop_window_stack_switch_overlay_timer();
  1528. remove_window_stack_switch_overlays();
  1529. }
  1530. VERIFY(!m_window_stack_transition_animation);
  1531. m_window_stack_transition_animation = Animation::create();
  1532. m_window_stack_transition_animation->set_duration(250);
  1533. m_window_stack_transition_animation->on_update = [this, delta_x, delta_y](float progress, Gfx::Painter&, Screen&, Gfx::DisjointIntRectSet&) {
  1534. VERIFY(m_transitioning_to_window_stack);
  1535. VERIFY(m_current_window_stack);
  1536. // Set transition offset for the window stack we're transitioning out of
  1537. auto previous_transition_offset_from = m_current_window_stack->transition_offset();
  1538. Gfx::IntPoint transition_offset_from { (float)delta_x * progress, (float)delta_y * progress };
  1539. if (previous_transition_offset_from == transition_offset_from)
  1540. return;
  1541. {
  1542. // we need to render both, the existing dirty rectangles as well as where we're shifting to
  1543. auto translated_dirty_rects = m_dirty_screen_rects.clone();
  1544. auto transition_delta = transition_offset_from - previous_transition_offset_from;
  1545. translated_dirty_rects.translate_by(transition_delta);
  1546. m_dirty_screen_rects.add(translated_dirty_rects.intersected(Screen::bounding_rect()));
  1547. }
  1548. m_current_window_stack->set_transition_offset({}, transition_offset_from);
  1549. // Set transition offset for the window stack we're transitioning to
  1550. Gfx::IntPoint transition_offset_to { (float)-delta_x * (1.0f - progress), (float)-delta_y * (1.0f - progress) };
  1551. m_transitioning_to_window_stack->set_transition_offset({}, transition_offset_to);
  1552. invalidate_occlusions();
  1553. // Rather than invalidating the entire we could invalidate all render rectangles
  1554. // that are affected by the transition offset before and after changing it.
  1555. invalidate_screen();
  1556. };
  1557. m_window_stack_transition_animation->on_stop = [this] {
  1558. finish_window_stack_switch();
  1559. };
  1560. m_window_stack_transition_animation->start();
  1561. }
  1562. }