Compositor.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "Compositor.h"
  27. #include "ClientConnection.h"
  28. #include "Event.h"
  29. #include "EventLoop.h"
  30. #include "Screen.h"
  31. #include "Window.h"
  32. #include "WindowManager.h"
  33. #include <AK/Debug.h>
  34. #include <AK/Memory.h>
  35. #include <AK/ScopeGuard.h>
  36. #include <LibCore/Timer.h>
  37. #include <LibGfx/Font.h>
  38. #include <LibGfx/Painter.h>
  39. #include <LibGfx/StylePainter.h>
  40. #include <LibThread/BackgroundAction.h>
  41. namespace WindowServer {
  42. Compositor& Compositor::the()
  43. {
  44. static Compositor s_the;
  45. return s_the;
  46. }
  47. static WallpaperMode mode_to_enum(const String& name)
  48. {
  49. if (name == "simple")
  50. return WallpaperMode::Simple;
  51. if (name == "tile")
  52. return WallpaperMode::Tile;
  53. if (name == "center")
  54. return WallpaperMode::Center;
  55. if (name == "stretch")
  56. return WallpaperMode::Stretch;
  57. return WallpaperMode::Simple;
  58. }
  59. Compositor::Compositor()
  60. {
  61. m_display_link_notify_timer = add<Core::Timer>(
  62. 1000 / 60, [this] {
  63. notify_display_links();
  64. });
  65. m_display_link_notify_timer->stop();
  66. m_compose_timer = Core::Timer::create_single_shot(
  67. 1000 / 60,
  68. [this] {
  69. compose();
  70. },
  71. this);
  72. m_immediate_compose_timer = Core::Timer::create_single_shot(
  73. 0,
  74. [this] {
  75. compose();
  76. },
  77. this);
  78. m_screen_can_set_buffer = Screen::the().can_set_buffer();
  79. init_bitmaps();
  80. }
  81. void Compositor::init_bitmaps()
  82. {
  83. auto& screen = Screen::the();
  84. auto size = screen.size();
  85. m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGB32, size, screen.scale_factor(), screen.pitch(), screen.scanline(0));
  86. m_front_painter = make<Gfx::Painter>(*m_front_bitmap);
  87. if (m_screen_can_set_buffer)
  88. m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGB32, size, screen.scale_factor(), screen.pitch(), screen.scanline(screen.physical_height()));
  89. else
  90. m_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, size, screen.scale_factor());
  91. m_back_painter = make<Gfx::Painter>(*m_back_bitmap);
  92. m_temp_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, size, screen.scale_factor());
  93. m_temp_painter = make<Gfx::Painter>(*m_temp_bitmap);
  94. m_buffers_are_flipped = false;
  95. invalidate_screen();
  96. }
  97. void Compositor::did_construct_window_manager(Badge<WindowManager>)
  98. {
  99. auto& wm = WindowManager::the();
  100. m_wallpaper_mode = mode_to_enum(wm.config()->read_entry("Background", "Mode", "simple"));
  101. m_custom_background_color = Color::from_string(wm.config()->read_entry("Background", "Color", ""));
  102. invalidate_screen();
  103. invalidate_occlusions();
  104. compose();
  105. }
  106. void Compositor::compose()
  107. {
  108. auto& wm = WindowManager::the();
  109. auto& ws = Screen::the();
  110. {
  111. auto& current_cursor = wm.active_cursor();
  112. if (m_current_cursor != &current_cursor)
  113. change_cursor(&current_cursor);
  114. }
  115. if (!m_invalidated_any) {
  116. // nothing dirtied since the last compose pass.
  117. return;
  118. }
  119. if (m_occlusions_dirty) {
  120. m_occlusions_dirty = false;
  121. recompute_occlusions();
  122. }
  123. auto dirty_screen_rects = move(m_dirty_screen_rects);
  124. dirty_screen_rects.add(m_last_geometry_label_damage_rect.intersected(ws.rect()));
  125. dirty_screen_rects.add(m_last_dnd_rect.intersected(ws.rect()));
  126. if (m_invalidated_cursor) {
  127. if (wm.dnd_client())
  128. dirty_screen_rects.add(wm.dnd_rect().intersected(ws.rect()));
  129. }
  130. // Mark window regions as dirty that need to be re-rendered
  131. wm.for_each_visible_window_from_back_to_front([&](Window& window) {
  132. auto frame_rect = window.frame().render_rect();
  133. for (auto& dirty_rect : dirty_screen_rects.rects()) {
  134. auto invalidate_rect = dirty_rect.intersected(frame_rect);
  135. if (!invalidate_rect.is_empty()) {
  136. auto inner_rect_offset = window.rect().location() - frame_rect.location();
  137. invalidate_rect.move_by(-(frame_rect.location() + inner_rect_offset));
  138. window.invalidate_no_notify(invalidate_rect);
  139. m_invalidated_window = true;
  140. }
  141. }
  142. window.prepare_dirty_rects();
  143. return IterationDecision::Continue;
  144. });
  145. // Any windows above or below a given window that need to be re-rendered
  146. // also require us to re-render that window's intersecting area, regardless
  147. // of whether that window has any dirty rectangles
  148. wm.for_each_visible_window_from_back_to_front([&](Window& window) {
  149. auto& transparency_rects = window.transparency_rects();
  150. if (transparency_rects.is_empty())
  151. return IterationDecision::Continue;
  152. auto frame_rect = window.frame().render_rect();
  153. auto& dirty_rects = window.dirty_rects();
  154. wm.for_each_visible_window_from_back_to_front([&](Window& w) {
  155. if (&w == &window)
  156. return IterationDecision::Continue;
  157. auto frame_rect2 = w.frame().render_rect();
  158. if (!frame_rect2.intersects(frame_rect))
  159. return IterationDecision::Continue;
  160. transparency_rects.for_each_intersected(w.dirty_rects(), [&](const Gfx::IntRect& intersected_dirty) {
  161. dirty_rects.add(intersected_dirty);
  162. return IterationDecision::Continue;
  163. });
  164. return IterationDecision::Continue;
  165. });
  166. return IterationDecision::Continue;
  167. });
  168. Color background_color = wm.palette().desktop_background();
  169. if (m_custom_background_color.has_value())
  170. background_color = m_custom_background_color.value();
  171. if constexpr (COMPOSE_DEBUG) {
  172. dbgln("COMPOSE: invalidated: window: {} cursor: {}, any: {}", m_invalidated_window, m_invalidated_cursor, m_invalidated_any);
  173. for (auto& r : dirty_screen_rects.rects())
  174. dbgln("dirty screen: {}", r);
  175. }
  176. Gfx::DisjointRectSet flush_rects;
  177. Gfx::DisjointRectSet flush_transparent_rects;
  178. Gfx::DisjointRectSet flush_special_rects;
  179. auto cursor_rect = current_cursor_rect();
  180. bool need_to_draw_cursor = false;
  181. auto back_painter = *m_back_painter;
  182. auto temp_painter = *m_temp_painter;
  183. auto check_restore_cursor_back = [&](const Gfx::IntRect& rect) {
  184. if (!need_to_draw_cursor && rect.intersects(cursor_rect)) {
  185. // Restore what's behind the cursor if anything touches the area of the cursor
  186. need_to_draw_cursor = true;
  187. restore_cursor_back();
  188. }
  189. };
  190. auto prepare_rect = [&](const Gfx::IntRect& rect) {
  191. dbgln_if(COMPOSE_DEBUG, " -> flush opaque: {}", rect);
  192. ASSERT(!flush_rects.intersects(rect));
  193. ASSERT(!flush_transparent_rects.intersects(rect));
  194. flush_rects.add(rect);
  195. check_restore_cursor_back(rect);
  196. };
  197. auto prepare_transparency_rect = [&](const Gfx::IntRect& rect) {
  198. dbgln_if(COMPOSE_DEBUG, " -> flush transparent: {}", rect);
  199. ASSERT(!flush_rects.intersects(rect));
  200. for (auto& r : flush_transparent_rects.rects()) {
  201. if (r == rect)
  202. return;
  203. }
  204. flush_transparent_rects.add(rect);
  205. check_restore_cursor_back(rect);
  206. };
  207. if (!m_cursor_back_bitmap || m_invalidated_cursor)
  208. check_restore_cursor_back(cursor_rect);
  209. auto paint_wallpaper = [&](Gfx::Painter& painter, const Gfx::IntRect& rect) {
  210. // FIXME: If the wallpaper is opaque and covers the whole rect, no need to fill with color!
  211. painter.fill_rect(rect, background_color);
  212. if (m_wallpaper) {
  213. if (m_wallpaper_mode == WallpaperMode::Simple) {
  214. painter.blit(rect.location(), *m_wallpaper, rect);
  215. } else if (m_wallpaper_mode == WallpaperMode::Center) {
  216. Gfx::IntPoint offset { (ws.width() - m_wallpaper->width()) / 2, (ws.height() - m_wallpaper->height()) / 2 };
  217. painter.blit_offset(rect.location(), *m_wallpaper, rect, offset);
  218. } else if (m_wallpaper_mode == WallpaperMode::Tile) {
  219. painter.draw_tiled_bitmap(rect, *m_wallpaper);
  220. } else if (m_wallpaper_mode == WallpaperMode::Stretch) {
  221. float hscale = (float)m_wallpaper->width() / (float)ws.width();
  222. float vscale = (float)m_wallpaper->height() / (float)ws.height();
  223. // TODO: this may look ugly, we should scale to a backing bitmap and then blit
  224. auto src_rect = Gfx::FloatRect { rect.x() * hscale, rect.y() * vscale, rect.width() * hscale, rect.height() * vscale };
  225. painter.draw_scaled_bitmap(rect, *m_wallpaper, src_rect);
  226. } else {
  227. ASSERT_NOT_REACHED();
  228. }
  229. }
  230. };
  231. m_opaque_wallpaper_rects.for_each_intersected(dirty_screen_rects, [&](const Gfx::IntRect& render_rect) {
  232. dbgln_if(COMPOSE_DEBUG, " render wallpaper opaque: {}", render_rect);
  233. prepare_rect(render_rect);
  234. paint_wallpaper(back_painter, render_rect);
  235. return IterationDecision::Continue;
  236. });
  237. auto compose_window = [&](Window& window) -> IterationDecision {
  238. auto frame_rect = window.frame().render_rect();
  239. if (!frame_rect.intersects(ws.rect()))
  240. return IterationDecision::Continue;
  241. auto frame_rects = frame_rect.shatter(window.rect());
  242. dbgln_if(COMPOSE_DEBUG, " window {} frame rect: {}", window.title(), frame_rect);
  243. RefPtr<Gfx::Bitmap> backing_store = window.backing_store();
  244. auto compose_window_rect = [&](Gfx::Painter& painter, const Gfx::IntRect& rect) {
  245. if (!window.is_fullscreen()) {
  246. rect.for_each_intersected(frame_rects, [&](const Gfx::IntRect& intersected_rect) {
  247. Gfx::PainterStateSaver saver(painter);
  248. painter.add_clip_rect(intersected_rect);
  249. dbgln_if(COMPOSE_DEBUG, " render frame: {}", intersected_rect);
  250. window.frame().paint(painter, intersected_rect);
  251. return IterationDecision::Continue;
  252. });
  253. }
  254. if (!backing_store) {
  255. if (window.is_opaque())
  256. painter.fill_rect(window.rect().intersected(rect), wm.palette().window());
  257. return;
  258. }
  259. // Decide where we would paint this window's backing store.
  260. // This is subtly different from widow.rect(), because window
  261. // size may be different from its backing store size. This
  262. // happens when the window has been resized and the client
  263. // has not yet attached a new backing store. In this case,
  264. // we want to try to blit the backing store at the same place
  265. // it was previously, and fill the rest of the window with its
  266. // background color.
  267. Gfx::IntRect backing_rect;
  268. backing_rect.set_size(backing_store->size());
  269. switch (WindowManager::the().resize_direction_of_window(window)) {
  270. case ResizeDirection::None:
  271. case ResizeDirection::Right:
  272. case ResizeDirection::Down:
  273. case ResizeDirection::DownRight:
  274. backing_rect.set_location(window.rect().location());
  275. break;
  276. case ResizeDirection::Left:
  277. case ResizeDirection::Up:
  278. case ResizeDirection::UpLeft:
  279. backing_rect.set_right_without_resize(window.rect().right());
  280. backing_rect.set_bottom_without_resize(window.rect().bottom());
  281. break;
  282. case ResizeDirection::UpRight:
  283. backing_rect.set_left(window.rect().left());
  284. backing_rect.set_bottom_without_resize(window.rect().bottom());
  285. break;
  286. case ResizeDirection::DownLeft:
  287. backing_rect.set_right_without_resize(window.rect().right());
  288. backing_rect.set_top(window.rect().top());
  289. break;
  290. }
  291. Gfx::IntRect dirty_rect_in_backing_coordinates = rect.intersected(window.rect())
  292. .intersected(backing_rect)
  293. .translated(-backing_rect.location());
  294. if (dirty_rect_in_backing_coordinates.is_empty())
  295. return;
  296. auto dst = backing_rect.location().translated(dirty_rect_in_backing_coordinates.location());
  297. if (window.client() && window.client()->is_unresponsive()) {
  298. painter.blit_filtered(dst, *backing_store, dirty_rect_in_backing_coordinates, [](Color src) {
  299. return src.to_grayscale().darkened(0.75f);
  300. });
  301. } else {
  302. painter.blit(dst, *backing_store, dirty_rect_in_backing_coordinates, window.opacity());
  303. }
  304. if (window.is_opaque()) {
  305. for (auto background_rect : window.rect().shatter(backing_rect))
  306. painter.fill_rect(background_rect, wm.palette().window());
  307. }
  308. };
  309. auto& dirty_rects = window.dirty_rects();
  310. if constexpr (COMPOSE_DEBUG) {
  311. for (auto& dirty_rect : dirty_rects.rects())
  312. dbgln(" dirty: {}", dirty_rect);
  313. for (auto& r : window.opaque_rects().rects())
  314. dbgln(" opaque: {}", r);
  315. for (auto& r : window.transparency_rects().rects())
  316. dbgln(" transparent: {}", r);
  317. }
  318. // Render opaque portions directly to the back buffer
  319. auto& opaque_rects = window.opaque_rects();
  320. if (!opaque_rects.is_empty()) {
  321. opaque_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
  322. dbgln_if(COMPOSE_DEBUG, " render opaque: {}", render_rect);
  323. prepare_rect(render_rect);
  324. Gfx::PainterStateSaver saver(back_painter);
  325. back_painter.add_clip_rect(render_rect);
  326. compose_window_rect(back_painter, render_rect);
  327. return IterationDecision::Continue;
  328. });
  329. }
  330. // Render the wallpaper for any transparency directly covering
  331. // the wallpaper
  332. auto& transparency_wallpaper_rects = window.transparency_wallpaper_rects();
  333. if (!transparency_wallpaper_rects.is_empty()) {
  334. transparency_wallpaper_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
  335. dbgln_if(COMPOSE_DEBUG, " render wallpaper: {}", render_rect);
  336. prepare_transparency_rect(render_rect);
  337. paint_wallpaper(temp_painter, render_rect);
  338. return IterationDecision::Continue;
  339. });
  340. }
  341. auto& transparency_rects = window.transparency_rects();
  342. if (!transparency_rects.is_empty()) {
  343. transparency_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
  344. dbgln_if(COMPOSE_DEBUG, " render transparent: {}", render_rect);
  345. prepare_transparency_rect(render_rect);
  346. Gfx::PainterStateSaver saver(temp_painter);
  347. temp_painter.add_clip_rect(render_rect);
  348. compose_window_rect(temp_painter, render_rect);
  349. return IterationDecision::Continue;
  350. });
  351. }
  352. return IterationDecision::Continue;
  353. };
  354. // Paint the window stack.
  355. if (m_invalidated_window) {
  356. if (auto* fullscreen_window = wm.active_fullscreen_window()) {
  357. compose_window(*fullscreen_window);
  358. } else {
  359. wm.for_each_visible_window_from_back_to_front([&](Window& window) {
  360. compose_window(window);
  361. window.clear_dirty_rects();
  362. return IterationDecision::Continue;
  363. });
  364. }
  365. // Check that there are no overlapping transparent and opaque flush rectangles
  366. ASSERT(![&]() {
  367. for (auto& rect_transparent : flush_transparent_rects.rects()) {
  368. for (auto& rect_opaque : flush_rects.rects()) {
  369. if (rect_opaque.intersects(rect_transparent)) {
  370. dbgln("Transparent rect {} overlaps opaque rect: {}: {}", rect_transparent, rect_opaque, rect_opaque.intersected(rect_transparent));
  371. return true;
  372. }
  373. }
  374. }
  375. return false;
  376. }());
  377. // Copy anything rendered to the temporary buffer to the back buffer
  378. for (auto& rect : flush_transparent_rects.rects())
  379. back_painter.blit(rect.location(), *m_temp_bitmap, rect);
  380. Gfx::IntRect geometry_label_damage_rect;
  381. if (draw_geometry_label(geometry_label_damage_rect))
  382. flush_special_rects.add(geometry_label_damage_rect);
  383. }
  384. m_invalidated_any = false;
  385. m_invalidated_window = false;
  386. m_invalidated_cursor = false;
  387. if (wm.dnd_client()) {
  388. auto dnd_rect = wm.dnd_rect();
  389. // TODO: render once into a backing bitmap, then just blit...
  390. auto render_dnd = [&]() {
  391. back_painter.fill_rect(dnd_rect, wm.palette().selection().with_alpha(200));
  392. back_painter.draw_rect(dnd_rect, wm.palette().selection());
  393. if (!wm.dnd_text().is_empty()) {
  394. auto text_rect = dnd_rect;
  395. if (wm.dnd_bitmap())
  396. text_rect.move_by(wm.dnd_bitmap()->width() + 8, 0);
  397. back_painter.draw_text(text_rect, wm.dnd_text(), Gfx::TextAlignment::CenterLeft, wm.palette().selection_text());
  398. }
  399. if (wm.dnd_bitmap()) {
  400. back_painter.blit(dnd_rect.top_left().translated(4, 4), *wm.dnd_bitmap(), wm.dnd_bitmap()->rect());
  401. }
  402. };
  403. dirty_screen_rects.for_each_intersected(dnd_rect, [&](const Gfx::IntRect& render_rect) {
  404. Gfx::PainterStateSaver saver(back_painter);
  405. back_painter.add_clip_rect(render_rect);
  406. render_dnd();
  407. return IterationDecision::Continue;
  408. });
  409. flush_transparent_rects.for_each_intersected(dnd_rect, [&](const Gfx::IntRect& render_rect) {
  410. Gfx::PainterStateSaver saver(back_painter);
  411. back_painter.add_clip_rect(render_rect);
  412. render_dnd();
  413. return IterationDecision::Continue;
  414. });
  415. m_last_dnd_rect = dnd_rect;
  416. } else {
  417. if (!m_last_dnd_rect.is_empty()) {
  418. invalidate_screen(m_last_dnd_rect);
  419. m_last_dnd_rect = {};
  420. }
  421. }
  422. run_animations(flush_special_rects);
  423. if (need_to_draw_cursor) {
  424. flush_rects.add(cursor_rect);
  425. if (cursor_rect != m_last_cursor_rect)
  426. flush_rects.add(m_last_cursor_rect);
  427. draw_cursor(cursor_rect);
  428. }
  429. if (m_flash_flush) {
  430. for (auto& rect : flush_rects.rects())
  431. m_front_painter->fill_rect(rect, Color::Yellow);
  432. }
  433. if (m_screen_can_set_buffer)
  434. flip_buffers();
  435. for (auto& rect : flush_rects.rects())
  436. flush(rect);
  437. for (auto& rect : flush_transparent_rects.rects())
  438. flush(rect);
  439. for (auto& rect : flush_special_rects.rects())
  440. flush(rect);
  441. }
  442. void Compositor::flush(const Gfx::IntRect& a_rect)
  443. {
  444. auto rect = Gfx::IntRect::intersection(a_rect, Screen::the().rect());
  445. // Almost everything in Compositor is in logical coordinates, with the painters having
  446. // a scale applied. But this routine accesses the backbuffer pixels directly, so it
  447. // must work in physical coordinates.
  448. rect = rect * Screen::the().scale_factor();
  449. Gfx::RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x();
  450. Gfx::RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
  451. size_t pitch = m_back_bitmap->pitch();
  452. // NOTE: The meaning of a flush depends on whether we can flip buffers or not.
  453. //
  454. // If flipping is supported, flushing means that we've flipped, and now we
  455. // copy the changed bits from the front buffer to the back buffer, to keep
  456. // them in sync.
  457. //
  458. // If flipping is not supported, flushing means that we copy the changed
  459. // rects from the backing bitmap to the display framebuffer.
  460. Gfx::RGBA32* to_ptr;
  461. const Gfx::RGBA32* from_ptr;
  462. if (m_screen_can_set_buffer) {
  463. to_ptr = back_ptr;
  464. from_ptr = front_ptr;
  465. } else {
  466. to_ptr = front_ptr;
  467. from_ptr = back_ptr;
  468. }
  469. for (int y = 0; y < rect.height(); ++y) {
  470. fast_u32_copy(to_ptr, from_ptr, rect.width());
  471. from_ptr = (const Gfx::RGBA32*)((const u8*)from_ptr + pitch);
  472. to_ptr = (Gfx::RGBA32*)((u8*)to_ptr + pitch);
  473. }
  474. }
  475. void Compositor::invalidate_screen()
  476. {
  477. invalidate_screen(Screen::the().rect());
  478. }
  479. void Compositor::invalidate_screen(const Gfx::IntRect& screen_rect)
  480. {
  481. m_dirty_screen_rects.add(screen_rect.intersected(Screen::the().rect()));
  482. if (m_invalidated_any)
  483. return;
  484. m_invalidated_any = true;
  485. m_invalidated_window = true;
  486. start_compose_async_timer();
  487. }
  488. void Compositor::invalidate_window()
  489. {
  490. if (m_invalidated_window)
  491. return;
  492. m_invalidated_window = true;
  493. m_invalidated_any = true;
  494. start_compose_async_timer();
  495. }
  496. void Compositor::start_compose_async_timer()
  497. {
  498. // We delay composition by a timer interval, but to not affect latency too
  499. // much, if a pending compose is not already scheduled, we also schedule an
  500. // immediate compose the next spin of the event loop.
  501. if (!m_compose_timer->is_active()) {
  502. m_compose_timer->start();
  503. m_immediate_compose_timer->start();
  504. }
  505. }
  506. bool Compositor::set_background_color(const String& background_color)
  507. {
  508. auto color = Color::from_string(background_color);
  509. if (!color.has_value())
  510. return false;
  511. m_custom_background_color = color;
  512. auto& wm = WindowManager::the();
  513. wm.config()->write_entry("Background", "Color", background_color);
  514. bool ret_val = wm.config()->sync();
  515. if (ret_val)
  516. Compositor::invalidate_screen();
  517. return ret_val;
  518. }
  519. bool Compositor::set_wallpaper_mode(const String& mode)
  520. {
  521. auto& wm = WindowManager::the();
  522. wm.config()->write_entry("Background", "Mode", mode);
  523. bool ret_val = wm.config()->sync();
  524. if (ret_val) {
  525. m_wallpaper_mode = mode_to_enum(mode);
  526. Compositor::invalidate_screen();
  527. }
  528. return ret_val;
  529. }
  530. bool Compositor::set_wallpaper(const String& path, Function<void(bool)>&& callback)
  531. {
  532. LibThread::BackgroundAction<RefPtr<Gfx::Bitmap>>::create(
  533. [path] {
  534. return Gfx::Bitmap::load_from_file(path);
  535. },
  536. [this, path, callback = move(callback)](RefPtr<Gfx::Bitmap> bitmap) {
  537. m_wallpaper_path = path;
  538. m_wallpaper = move(bitmap);
  539. invalidate_screen();
  540. callback(true);
  541. });
  542. return true;
  543. }
  544. void Compositor::flip_buffers()
  545. {
  546. ASSERT(m_screen_can_set_buffer);
  547. swap(m_front_bitmap, m_back_bitmap);
  548. swap(m_front_painter, m_back_painter);
  549. Screen::the().set_buffer(m_buffers_are_flipped ? 0 : 1);
  550. m_buffers_are_flipped = !m_buffers_are_flipped;
  551. }
  552. void Compositor::run_animations(Gfx::DisjointRectSet& flush_rects)
  553. {
  554. static const int minimize_animation_steps = 10;
  555. auto& painter = *m_back_painter;
  556. Gfx::PainterStateSaver saver(painter);
  557. painter.set_draw_op(Gfx::Painter::DrawOp::Invert);
  558. WindowManager::the().for_each_window([&](Window& window) {
  559. if (window.in_minimize_animation()) {
  560. int animation_index = window.minimize_animation_index();
  561. auto from_rect = window.is_minimized() ? window.frame().rect() : window.taskbar_rect();
  562. auto to_rect = window.is_minimized() ? window.taskbar_rect() : window.frame().rect();
  563. float x_delta_per_step = (float)(from_rect.x() - to_rect.x()) / minimize_animation_steps;
  564. float y_delta_per_step = (float)(from_rect.y() - to_rect.y()) / minimize_animation_steps;
  565. float width_delta_per_step = (float)(from_rect.width() - to_rect.width()) / minimize_animation_steps;
  566. float height_delta_per_step = (float)(from_rect.height() - to_rect.height()) / minimize_animation_steps;
  567. Gfx::IntRect rect {
  568. from_rect.x() - (int)(x_delta_per_step * animation_index),
  569. from_rect.y() - (int)(y_delta_per_step * animation_index),
  570. from_rect.width() - (int)(width_delta_per_step * animation_index),
  571. from_rect.height() - (int)(height_delta_per_step * animation_index)
  572. };
  573. dbgln_if(MINIMIZE_ANIMATION_DEBUG, "Minimize animation from {} to {} frame# {} {}", from_rect, to_rect, animation_index, rect);
  574. painter.draw_rect(rect, Color::Transparent); // Color doesn't matter, we draw inverted
  575. flush_rects.add(rect);
  576. invalidate_screen(rect);
  577. window.step_minimize_animation();
  578. if (window.minimize_animation_index() >= minimize_animation_steps)
  579. window.end_minimize_animation();
  580. }
  581. return IterationDecision::Continue;
  582. });
  583. }
  584. bool Compositor::set_resolution(int desired_width, int desired_height, int scale_factor)
  585. {
  586. auto screen_rect = Screen::the().rect();
  587. if (screen_rect.width() == desired_width && screen_rect.height() == desired_height && Screen::the().scale_factor() == scale_factor)
  588. return true;
  589. // Make sure it's impossible to set an invalid resolution
  590. if (!(desired_width >= 640 && desired_height >= 480 && scale_factor >= 1)) {
  591. dbgln("Compositor: Tried to set invalid resolution: {}x{}", desired_width, desired_height);
  592. return false;
  593. }
  594. int old_scale_factor = Screen::the().scale_factor();
  595. bool success = Screen::the().set_resolution(desired_width, desired_height, scale_factor);
  596. if (success && old_scale_factor != scale_factor)
  597. WindowManager::the().reload_icon_bitmaps_after_scale_change();
  598. init_bitmaps();
  599. invalidate_occlusions();
  600. compose();
  601. return success;
  602. }
  603. Gfx::IntRect Compositor::current_cursor_rect() const
  604. {
  605. auto& wm = WindowManager::the();
  606. auto& current_cursor = m_current_cursor ? *m_current_cursor : wm.active_cursor();
  607. return { Screen::the().cursor_location().translated(-current_cursor.params().hotspot()), current_cursor.size() };
  608. }
  609. void Compositor::invalidate_cursor(bool compose_immediately)
  610. {
  611. if (m_invalidated_cursor)
  612. return;
  613. m_invalidated_cursor = true;
  614. m_invalidated_any = true;
  615. if (compose_immediately)
  616. compose();
  617. else
  618. start_compose_async_timer();
  619. }
  620. bool Compositor::draw_geometry_label(Gfx::IntRect& geometry_label_damage_rect)
  621. {
  622. auto& wm = WindowManager::the();
  623. auto* window_being_moved_or_resized = wm.m_move_window ? wm.m_move_window.ptr() : (wm.m_resize_window ? wm.m_resize_window.ptr() : nullptr);
  624. if (!window_being_moved_or_resized) {
  625. m_last_geometry_label_damage_rect = {};
  626. return false;
  627. }
  628. auto geometry_string = window_being_moved_or_resized->rect().to_string();
  629. if (!window_being_moved_or_resized->size_increment().is_null()) {
  630. int width_steps = (window_being_moved_or_resized->width() - window_being_moved_or_resized->base_size().width()) / window_being_moved_or_resized->size_increment().width();
  631. int height_steps = (window_being_moved_or_resized->height() - window_being_moved_or_resized->base_size().height()) / window_being_moved_or_resized->size_increment().height();
  632. geometry_string = String::formatted("{} ({}x{})", geometry_string, width_steps, height_steps);
  633. }
  634. auto geometry_label_rect = Gfx::IntRect { 0, 0, wm.font().width(geometry_string) + 16, wm.font().glyph_height() + 10 };
  635. geometry_label_rect.center_within(window_being_moved_or_resized->rect());
  636. auto desktop_rect = wm.desktop_rect();
  637. if (geometry_label_rect.left() < desktop_rect.left())
  638. geometry_label_rect.set_left(desktop_rect.left());
  639. if (geometry_label_rect.top() < desktop_rect.top())
  640. geometry_label_rect.set_top(desktop_rect.top());
  641. if (geometry_label_rect.right() > desktop_rect.right())
  642. geometry_label_rect.set_right_without_resize(desktop_rect.right());
  643. if (geometry_label_rect.bottom() > desktop_rect.bottom())
  644. geometry_label_rect.set_bottom_without_resize(desktop_rect.bottom());
  645. auto& back_painter = *m_back_painter;
  646. back_painter.fill_rect(geometry_label_rect.translated(1, 1), Color(Color::Black).with_alpha(80));
  647. Gfx::StylePainter::paint_button(back_painter, geometry_label_rect.translated(-1, -1), wm.palette(), Gfx::ButtonStyle::Normal, false);
  648. back_painter.draw_text(geometry_label_rect.translated(-1, -1), geometry_string, Gfx::TextAlignment::Center, wm.palette().window_text());
  649. geometry_label_damage_rect = geometry_label_rect.inflated(2, 2);
  650. m_last_geometry_label_damage_rect = geometry_label_damage_rect;
  651. return true;
  652. }
  653. void Compositor::change_cursor(const Cursor* cursor)
  654. {
  655. if (m_current_cursor == cursor)
  656. return;
  657. m_current_cursor = cursor;
  658. m_current_cursor_frame = 0;
  659. if (m_cursor_timer) {
  660. m_cursor_timer->stop();
  661. m_cursor_timer = nullptr;
  662. }
  663. if (cursor && cursor->params().frames() > 1 && cursor->params().frame_ms() != 0) {
  664. m_cursor_timer = add<Core::Timer>(
  665. cursor->params().frame_ms(), [this, cursor] {
  666. if (m_current_cursor != cursor)
  667. return;
  668. auto frames = cursor->params().frames();
  669. if (++m_current_cursor_frame >= frames)
  670. m_current_cursor_frame = 0;
  671. invalidate_cursor(true);
  672. });
  673. }
  674. }
  675. void Compositor::draw_cursor(const Gfx::IntRect& cursor_rect)
  676. {
  677. auto& wm = WindowManager::the();
  678. if (!m_cursor_back_bitmap || m_cursor_back_bitmap->size() != cursor_rect.size() || m_cursor_back_bitmap->scale() != Screen::the().scale_factor()) {
  679. m_cursor_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, cursor_rect.size(), Screen::the().scale_factor());
  680. m_cursor_back_painter = make<Gfx::Painter>(*m_cursor_back_bitmap);
  681. }
  682. auto& current_cursor = m_current_cursor ? *m_current_cursor : wm.active_cursor();
  683. m_cursor_back_painter->blit({ 0, 0 }, *m_back_bitmap, current_cursor.rect().translated(cursor_rect.location()).intersected(Screen::the().rect()));
  684. m_back_painter->blit(cursor_rect.location(), current_cursor.bitmap(), current_cursor.source_rect(m_current_cursor_frame));
  685. m_last_cursor_rect = cursor_rect;
  686. }
  687. void Compositor::restore_cursor_back()
  688. {
  689. if (!m_cursor_back_bitmap || m_cursor_back_bitmap->scale() != m_back_bitmap->scale())
  690. return;
  691. auto last_cursor_rect = m_last_cursor_rect.intersected(Screen::the().rect());
  692. m_back_painter->blit(last_cursor_rect.location(), *m_cursor_back_bitmap, { { 0, 0 }, last_cursor_rect.size() });
  693. }
  694. void Compositor::notify_display_links()
  695. {
  696. ClientConnection::for_each_client([](auto& client) {
  697. client.notify_display_link({});
  698. });
  699. }
  700. void Compositor::increment_display_link_count(Badge<ClientConnection>)
  701. {
  702. ++m_display_link_count;
  703. if (m_display_link_count == 1)
  704. m_display_link_notify_timer->start();
  705. }
  706. void Compositor::decrement_display_link_count(Badge<ClientConnection>)
  707. {
  708. ASSERT(m_display_link_count);
  709. --m_display_link_count;
  710. if (!m_display_link_count)
  711. m_display_link_notify_timer->stop();
  712. }
  713. bool Compositor::any_opaque_window_above_this_one_contains_rect(const Window& a_window, const Gfx::IntRect& rect)
  714. {
  715. bool found_containing_window = false;
  716. bool checking = false;
  717. WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& window) {
  718. if (&window == &a_window) {
  719. checking = true;
  720. return IterationDecision::Continue;
  721. }
  722. if (!checking)
  723. return IterationDecision::Continue;
  724. if (!window.is_visible())
  725. return IterationDecision::Continue;
  726. if (window.is_minimized())
  727. return IterationDecision::Continue;
  728. if (!window.is_opaque())
  729. return IterationDecision::Continue;
  730. if (window.frame().render_rect().contains(rect)) {
  731. found_containing_window = true;
  732. return IterationDecision::Break;
  733. }
  734. return IterationDecision::Continue;
  735. });
  736. return found_containing_window;
  737. };
  738. void Compositor::recompute_occlusions()
  739. {
  740. auto& wm = WindowManager::the();
  741. wm.for_each_visible_window_from_back_to_front([&](Window& window) {
  742. if (wm.m_switcher.is_visible()) {
  743. window.set_occluded(false);
  744. } else {
  745. if (any_opaque_window_above_this_one_contains_rect(window, window.frame().rect()))
  746. window.set_occluded(true);
  747. else
  748. window.set_occluded(false);
  749. }
  750. return IterationDecision::Continue;
  751. });
  752. #if OCCLUSIONS_DEBUG
  753. dbgln("OCCLUSIONS:");
  754. #endif
  755. auto screen_rect = Screen::the().rect();
  756. if (auto* fullscreen_window = wm.active_fullscreen_window()) {
  757. WindowManager::the().for_each_visible_window_from_front_to_back([&](Window& w) {
  758. auto& visible_opaque = w.opaque_rects();
  759. auto& transparency_rects = w.transparency_rects();
  760. auto& transparency_wallpaper_rects = w.transparency_wallpaper_rects();
  761. if (&w == fullscreen_window) {
  762. if (w.is_opaque()) {
  763. visible_opaque = screen_rect;
  764. transparency_rects.clear();
  765. transparency_wallpaper_rects.clear();
  766. } else {
  767. visible_opaque.clear();
  768. transparency_rects = screen_rect;
  769. transparency_wallpaper_rects = screen_rect;
  770. }
  771. } else {
  772. visible_opaque.clear();
  773. transparency_rects.clear();
  774. transparency_wallpaper_rects.clear();
  775. }
  776. return IterationDecision::Continue;
  777. });
  778. m_opaque_wallpaper_rects.clear();
  779. } else {
  780. Gfx::DisjointRectSet visible_rects(screen_rect);
  781. bool have_transparent = false;
  782. WindowManager::the().for_each_visible_window_from_front_to_back([&](Window& w) {
  783. auto window_frame_rect = w.frame().render_rect().intersected(screen_rect);
  784. w.transparency_wallpaper_rects().clear();
  785. auto& visible_opaque = w.opaque_rects();
  786. auto& transparency_rects = w.transparency_rects();
  787. if (w.is_minimized() || window_frame_rect.is_empty()) {
  788. visible_opaque.clear();
  789. transparency_rects.clear();
  790. return IterationDecision::Continue;
  791. }
  792. Gfx::DisjointRectSet opaque_covering;
  793. if (w.is_opaque()) {
  794. transparency_rects.clear();
  795. if (w.frame().is_opaque()) {
  796. visible_opaque = visible_rects.intersected(window_frame_rect);
  797. } else {
  798. auto window_rect = w.rect().intersected(screen_rect);
  799. visible_opaque = visible_rects.intersected(window_rect);
  800. transparency_rects.add_many(window_frame_rect.shatter(window_rect));
  801. }
  802. } else {
  803. visible_opaque.clear();
  804. if (w.frame().is_opaque()) {
  805. auto window_rect = w.rect().intersected(screen_rect);
  806. visible_opaque.add_many(window_frame_rect.shatter(window_rect));
  807. transparency_rects = visible_rects.intersected(window_rect);
  808. } else {
  809. transparency_rects = visible_rects.intersected(window_frame_rect);
  810. }
  811. }
  812. bool found_this_window = false;
  813. WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& w2) {
  814. if (!found_this_window) {
  815. if (&w == &w2)
  816. found_this_window = true;
  817. return IterationDecision::Continue;
  818. }
  819. if (w2.is_minimized())
  820. return IterationDecision::Continue;
  821. auto window_frame_rect2 = w2.frame().render_rect().intersected(screen_rect);
  822. auto covering_rect = window_frame_rect2.intersected(window_frame_rect);
  823. if (covering_rect.is_empty())
  824. return IterationDecision::Continue;
  825. auto add_opaque = [&](const Gfx::IntRect& covering) {
  826. opaque_covering.add(covering);
  827. if (!visible_opaque.is_empty()) {
  828. auto uncovered_opaque = visible_opaque.shatter(covering);
  829. visible_opaque = move(uncovered_opaque);
  830. }
  831. if (!transparency_rects.is_empty()) {
  832. auto uncovered_transparency = transparency_rects.shatter(covering);
  833. transparency_rects = move(uncovered_transparency);
  834. }
  835. };
  836. auto add_transparent = [&](const Gfx::IntRect& covering) {
  837. visible_rects.for_each_intersected(covering, [&](const Gfx::IntRect& intersected) {
  838. transparency_rects.add(intersected);
  839. if (!visible_opaque.is_empty()) {
  840. auto uncovered_opaque = visible_opaque.shatter(intersected);
  841. visible_opaque = move(uncovered_opaque);
  842. }
  843. return IterationDecision::Continue;
  844. });
  845. };
  846. if (w2.is_opaque()) {
  847. if (w2.frame().is_opaque()) {
  848. if (opaque_covering.contains(covering_rect)) {
  849. // This window (including frame) is entirely covered by another opaque window
  850. visible_opaque.clear();
  851. transparency_rects.clear();
  852. return IterationDecision::Break;
  853. }
  854. add_opaque(covering_rect);
  855. } else {
  856. auto covering_window_rect = covering_rect.intersected(w2.rect());
  857. add_opaque(covering_window_rect);
  858. for (auto& covering_frame_rect : covering_rect.shatter(covering_window_rect))
  859. add_transparent(covering_frame_rect);
  860. }
  861. } else {
  862. if (w2.frame().is_opaque()) {
  863. auto covering_window_rect = covering_rect.intersected(w2.rect());
  864. add_transparent(covering_window_rect);
  865. for (auto& covering_frame_rect : covering_rect.shatter(covering_window_rect))
  866. add_opaque(covering_frame_rect);
  867. } else {
  868. add_transparent(covering_rect);
  869. }
  870. }
  871. return IterationDecision::Continue;
  872. });
  873. if (!transparency_rects.is_empty())
  874. have_transparent = true;
  875. ASSERT(!visible_opaque.intersects(transparency_rects));
  876. // Determine visible area for the window below
  877. if (w.is_opaque()) {
  878. if (w.frame().is_opaque()) {
  879. auto visible_rects_below_window = visible_rects.shatter(window_frame_rect);
  880. visible_rects = move(visible_rects_below_window);
  881. } else {
  882. auto visible_rects_below_window = visible_rects.shatter(w.rect().intersected(screen_rect));
  883. visible_rects = move(visible_rects_below_window);
  884. }
  885. }
  886. return IterationDecision::Continue;
  887. });
  888. if (have_transparent) {
  889. // Determine what transparent window areas need to render the wallpaper first
  890. WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& w) {
  891. auto& transparency_wallpaper_rects = w.transparency_wallpaper_rects();
  892. if (w.is_minimized()) {
  893. transparency_wallpaper_rects.clear();
  894. return IterationDecision::Continue;
  895. }
  896. Gfx::DisjointRectSet& transparency_rects = w.transparency_rects();
  897. if (transparency_rects.is_empty()) {
  898. transparency_wallpaper_rects.clear();
  899. return IterationDecision::Continue;
  900. }
  901. transparency_wallpaper_rects = visible_rects.intersected(transparency_rects);
  902. auto remaining_visible = visible_rects.shatter(transparency_wallpaper_rects);
  903. visible_rects = move(remaining_visible);
  904. return IterationDecision::Continue;
  905. });
  906. }
  907. m_opaque_wallpaper_rects = move(visible_rects);
  908. }
  909. if constexpr (OCCLUSIONS_DEBUG) {
  910. for (auto& r : m_opaque_wallpaper_rects.rects())
  911. dbgln(" wallpaper opaque: {}", r);
  912. }
  913. wm.for_each_visible_window_from_back_to_front([&](Window& w) {
  914. auto window_frame_rect = w.frame().render_rect().intersected(screen_rect);
  915. if (w.is_minimized() || window_frame_rect.is_empty())
  916. return IterationDecision::Continue;
  917. if constexpr (OCCLUSIONS_DEBUG) {
  918. dbgln(" Window {} frame rect: {}", w.title(), window_frame_rect);
  919. for (auto& r : w.opaque_rects().rects())
  920. dbgln(" opaque: {}", r);
  921. for (auto& r : w.transparency_wallpaper_rects().rects())
  922. dbgln(" transparent wallpaper: {}", r);
  923. for (auto& r : w.transparency_rects().rects())
  924. dbgln(" transparent: {}", r);
  925. }
  926. ASSERT(!w.opaque_rects().intersects(m_opaque_wallpaper_rects));
  927. ASSERT(!w.transparency_rects().intersects(m_opaque_wallpaper_rects));
  928. ASSERT(!w.transparency_wallpaper_rects().intersects(m_opaque_wallpaper_rects));
  929. return IterationDecision::Continue;
  930. });
  931. }
  932. }