mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:32:45 +00:00 
			
		
		
		
	WindowServer: Factor out compositing from WSWindowManager into WSCompositor.
This is far from finished and the two classes are awkwardly grabbing at each other's innards, but here's a first step in the right direction.
This commit is contained in:
		
							parent
							
								
									508007f1dd
								
							
						
					
					
						commit
						ad908f1395
					
				
					 11 changed files with 487 additions and 426 deletions
				
			
		|  | @ -1,5 +1,6 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <AK/Assertions.h> | ||||||
| #include <AK/Types.h> | #include <AK/Types.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __clang__ | #ifdef __clang__ | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ WINDOWSERVER_OBJS = \ | ||||||
|     WSWindowFrame.o \
 |     WSWindowFrame.o \
 | ||||||
|     WSButton.o \
 |     WSButton.o \
 | ||||||
|     WSCPUMonitor.o \
 |     WSCPUMonitor.o \
 | ||||||
|  |     WSCompositor.o \
 | ||||||
|     main.o |     main.o | ||||||
| 
 | 
 | ||||||
| APP = WindowServer | APP = WindowServer | ||||||
|  |  | ||||||
|  | @ -1,20 +1,21 @@ | ||||||
|  | #include <SharedBuffer.h> | ||||||
|  | #include <WindowServer/WSAPITypes.h> | ||||||
| #include <WindowServer/WSClientConnection.h> | #include <WindowServer/WSClientConnection.h> | ||||||
|  | #include <WindowServer/WSClipboard.h> | ||||||
|  | #include <WindowServer/WSCompositor.h> | ||||||
| #include <WindowServer/WSEventLoop.h> | #include <WindowServer/WSEventLoop.h> | ||||||
| #include <WindowServer/WSMenuBar.h> |  | ||||||
| #include <WindowServer/WSMenu.h> | #include <WindowServer/WSMenu.h> | ||||||
|  | #include <WindowServer/WSMenuBar.h> | ||||||
| #include <WindowServer/WSMenuItem.h> | #include <WindowServer/WSMenuItem.h> | ||||||
|  | #include <WindowServer/WSScreen.h> | ||||||
| #include <WindowServer/WSWindow.h> | #include <WindowServer/WSWindow.h> | ||||||
| #include <WindowServer/WSWindowManager.h> | #include <WindowServer/WSWindowManager.h> | ||||||
| #include <WindowServer/WSAPITypes.h> |  | ||||||
| #include <WindowServer/WSClipboard.h> |  | ||||||
| #include <WindowServer/WSScreen.h> |  | ||||||
| #include <WindowServer/WSWindowSwitcher.h> | #include <WindowServer/WSWindowSwitcher.h> | ||||||
| #include <SharedBuffer.h> | #include <errno.h> | ||||||
|  | #include <stdio.h> | ||||||
| #include <sys/ioctl.h> | #include <sys/ioctl.h> | ||||||
| #include <sys/uio.h> | #include <sys/uio.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <errno.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| 
 | 
 | ||||||
| HashMap<int, WSClientConnection*>* s_connections; | HashMap<int, WSClientConnection*>* s_connections; | ||||||
| 
 | 
 | ||||||
|  | @ -342,7 +343,7 @@ void WSClientConnection::handle_request(const WSAPISetWindowOpacityRequest& requ | ||||||
| 
 | 
 | ||||||
| void WSClientConnection::handle_request(const WSAPISetWallpaperRequest& request) | void WSClientConnection::handle_request(const WSAPISetWallpaperRequest& request) | ||||||
| { | { | ||||||
|     WSWindowManager::the().set_wallpaper(request.wallpaper(), [&] (bool success) { |     WSCompositor::the().set_wallpaper(request.wallpaper(), [&] (bool success) { | ||||||
|         WSAPI_ServerMessage response; |         WSAPI_ServerMessage response; | ||||||
|         response.type = WSAPI_ServerMessage::Type::DidSetWallpaper; |         response.type = WSAPI_ServerMessage::Type::DidSetWallpaper; | ||||||
|         response.value = success; |         response.value = success; | ||||||
|  | @ -352,7 +353,7 @@ void WSClientConnection::handle_request(const WSAPISetWallpaperRequest& request) | ||||||
| 
 | 
 | ||||||
| void WSClientConnection::handle_request(const WSAPIGetWallpaperRequest&) | void WSClientConnection::handle_request(const WSAPIGetWallpaperRequest&) | ||||||
| { | { | ||||||
|     auto path = WSWindowManager::the().wallpaper_path(); |     auto path = WSCompositor::the().wallpaper_path(); | ||||||
|     WSAPI_ServerMessage response; |     WSAPI_ServerMessage response; | ||||||
|     response.type = WSAPI_ServerMessage::Type::DidGetWallpaper; |     response.type = WSAPI_ServerMessage::Type::DidGetWallpaper; | ||||||
|     ASSERT(path.length() < (int)sizeof(response.text)); |     ASSERT(path.length() < (int)sizeof(response.text)); | ||||||
|  |  | ||||||
							
								
								
									
										334
									
								
								Servers/WindowServer/WSCompositor.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								Servers/WindowServer/WSCompositor.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,334 @@ | ||||||
|  | #include "WSCompositor.h" | ||||||
|  | #include "WSEvent.h" | ||||||
|  | #include "WSEventLoop.h" | ||||||
|  | #include "WSScreen.h" | ||||||
|  | #include "WSWindow.h" | ||||||
|  | #include "WSWindowManager.h" | ||||||
|  | #include <SharedGraphics/Font.h> | ||||||
|  | #include <SharedGraphics/PNGLoader.h> | ||||||
|  | #include <SharedGraphics/Painter.h> | ||||||
|  | 
 | ||||||
|  | WSCompositor& WSCompositor::the() | ||||||
|  | { | ||||||
|  |     static WSCompositor s_the; | ||||||
|  |     return s_the; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | WSCompositor::WSCompositor() | ||||||
|  | { | ||||||
|  |     auto size = WSScreen::the().size(); | ||||||
|  |     m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, WSScreen::the().scanline(0)); | ||||||
|  |     m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, WSScreen::the().scanline(size.height())); | ||||||
|  | 
 | ||||||
|  |     m_front_painter = make<Painter>(*m_front_bitmap); | ||||||
|  |     m_back_painter = make<Painter>(*m_back_bitmap); | ||||||
|  | 
 | ||||||
|  |     m_wallpaper_path = "/res/wallpapers/retro.rgb"; | ||||||
|  |     m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::event(CEvent& event) | ||||||
|  | { | ||||||
|  |     if (event.type() == WSEvent::WM_DeferredCompose) { | ||||||
|  |         m_pending_compose_event = false; | ||||||
|  |         compose(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::compose() | ||||||
|  | { | ||||||
|  |     auto& wm = WSWindowManager::the(); | ||||||
|  | 
 | ||||||
|  |     auto dirty_rects = move(m_dirty_rects); | ||||||
|  |     dirty_rects.add(Rect::intersection(m_last_geometry_label_rect, WSScreen::the().rect())); | ||||||
|  |     dirty_rects.add(Rect::intersection(m_last_cursor_rect, WSScreen::the().rect())); | ||||||
|  |     dirty_rects.add(Rect::intersection(current_cursor_rect(), WSScreen::the().rect())); | ||||||
|  | #ifdef DEBUG_COUNTERS | ||||||
|  |     dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.rects().size()); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     auto any_dirty_rect_intersects_window = [&dirty_rects] (const WSWindow& window) { | ||||||
|  |         auto window_frame_rect = window.frame().rect(); | ||||||
|  |         for (auto& dirty_rect : dirty_rects.rects()) { | ||||||
|  |             if (dirty_rect.intersects(window_frame_rect)) | ||||||
|  |                 return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     for (auto& dirty_rect : dirty_rects.rects()) { | ||||||
|  |         if (wm.any_opaque_window_contains_rect(dirty_rect)) | ||||||
|  |             continue; | ||||||
|  |         if (!m_wallpaper) | ||||||
|  |             m_back_painter->fill_rect(dirty_rect, wm.m_background_color); | ||||||
|  |         else | ||||||
|  |             m_back_painter->blit(dirty_rect.location(), *m_wallpaper, dirty_rect); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto compose_window = [&] (WSWindow& window) -> IterationDecision { | ||||||
|  |         if (!any_dirty_rect_intersects_window(window)) | ||||||
|  |             return IterationDecision::Continue; | ||||||
|  |         PainterStateSaver saver(*m_back_painter); | ||||||
|  |         m_back_painter->add_clip_rect(window.frame().rect()); | ||||||
|  |         RetainPtr<GraphicsBitmap> backing_store = window.backing_store(); | ||||||
|  |         for (auto& dirty_rect : dirty_rects.rects()) { | ||||||
|  |             if (wm.any_opaque_window_above_this_one_contains_rect(window, dirty_rect)) | ||||||
|  |                 continue; | ||||||
|  |             PainterStateSaver saver(*m_back_painter); | ||||||
|  |             m_back_painter->add_clip_rect(dirty_rect); | ||||||
|  |             if (!backing_store) | ||||||
|  |                 m_back_painter->fill_rect(dirty_rect, window.background_color()); | ||||||
|  |             if (!window.is_fullscreen()) | ||||||
|  |                 window.frame().paint(*m_back_painter); | ||||||
|  |             if (!backing_store) | ||||||
|  |                 continue; | ||||||
|  |             Rect dirty_rect_in_window_coordinates = Rect::intersection(dirty_rect, window.rect()); | ||||||
|  |             if (dirty_rect_in_window_coordinates.is_empty()) | ||||||
|  |                 continue; | ||||||
|  |             dirty_rect_in_window_coordinates.move_by(-window.position()); | ||||||
|  |             auto dst = window.position(); | ||||||
|  |             dst.move_by(dirty_rect_in_window_coordinates.location()); | ||||||
|  | 
 | ||||||
|  |             m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity()); | ||||||
|  | 
 | ||||||
|  |             if (backing_store->width() < window.width()) { | ||||||
|  |                 Rect right_fill_rect { window.x() + backing_store->width(), window.y(), window.width() - backing_store->width(), window.height() }; | ||||||
|  |                 m_back_painter->fill_rect(right_fill_rect, window.background_color()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (backing_store->height() < window.height()) { | ||||||
|  |                 Rect bottom_fill_rect { window.x(), window.y() + backing_store->height(), window.width(), window.height() - backing_store->height() }; | ||||||
|  |                 m_back_painter->fill_rect(bottom_fill_rect, window.background_color()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return IterationDecision::Continue; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     if (auto* fullscreen_window = wm.active_fullscreen_window()) { | ||||||
|  |         compose_window(*fullscreen_window); | ||||||
|  |     } else { | ||||||
|  |         wm.for_each_visible_window_from_back_to_front([&] (WSWindow& window) { | ||||||
|  |             return compose_window(window); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         draw_geometry_label(); | ||||||
|  |         draw_menubar(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     draw_cursor(); | ||||||
|  | 
 | ||||||
|  |     if (m_flash_flush) { | ||||||
|  |         for (auto& rect : dirty_rects.rects()) | ||||||
|  |             m_front_painter->fill_rect(rect, Color::Yellow); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     flip_buffers(); | ||||||
|  |     for (auto& r : dirty_rects.rects()) | ||||||
|  |         flush(r); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::flush(const Rect& a_rect) | ||||||
|  | { | ||||||
|  |     auto rect = Rect::intersection(a_rect, WSScreen::the().rect()); | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG_COUNTERS | ||||||
|  |     dbgprintf("[WM] flush #%u (%d,%d %dx%d)\n", ++m_flush_count, rect.x(), rect.y(), rect.width(), rect.height()); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     const RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x(); | ||||||
|  |     RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x(); | ||||||
|  |     size_t pitch = m_back_bitmap->pitch(); | ||||||
|  | 
 | ||||||
|  |     for (int y = 0; y < rect.height(); ++y) { | ||||||
|  |         fast_dword_copy(back_ptr, front_ptr, rect.width()); | ||||||
|  |         front_ptr = (const RGBA32*)((const byte*)front_ptr + pitch); | ||||||
|  |         back_ptr = (RGBA32*)((byte*)back_ptr + pitch); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::invalidate() | ||||||
|  | { | ||||||
|  |     m_dirty_rects.clear_with_capacity(); | ||||||
|  |     invalidate(WSScreen::the().rect()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::invalidate(const Rect& a_rect) | ||||||
|  | { | ||||||
|  |     auto rect = Rect::intersection(a_rect, WSScreen::the().rect()); | ||||||
|  |     if (rect.is_empty()) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     m_dirty_rects.add(rect); | ||||||
|  | 
 | ||||||
|  |     if (!m_pending_compose_event) { | ||||||
|  |         WSEventLoop::the().post_event(*this, make<WSEvent>(WSEvent::WM_DeferredCompose)); | ||||||
|  |         m_pending_compose_event = true; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool WSCompositor::set_wallpaper(const String& path, Function<void(bool)>&& callback) | ||||||
|  | { | ||||||
|  |     struct Context { | ||||||
|  |         String path; | ||||||
|  |         RetainPtr<GraphicsBitmap> bitmap; | ||||||
|  |         Function<void(bool)> callback; | ||||||
|  |     }; | ||||||
|  |     auto context = make<Context>(); | ||||||
|  |     context->path = path; | ||||||
|  |     context->callback = move(callback); | ||||||
|  | 
 | ||||||
|  |     int rc = create_thread([] (void* ctx) -> int { | ||||||
|  |         OwnPtr<Context> context((Context*)ctx); | ||||||
|  |         context->bitmap = load_png(context->path); | ||||||
|  |         if (!context->bitmap) { | ||||||
|  |             context->callback(false); | ||||||
|  |             exit_thread(0); | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         the().deferred_invoke([context = move(context)] (auto&) { | ||||||
|  |             the().finish_setting_wallpaper(context->path, *context->bitmap); | ||||||
|  |             context->callback(true); | ||||||
|  |         }); | ||||||
|  |         exit_thread(0); | ||||||
|  |         return 0; | ||||||
|  |     }, context.leak_ptr()); | ||||||
|  |     ASSERT(rc == 0); | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::finish_setting_wallpaper(const String& path, Retained<GraphicsBitmap>&& bitmap) | ||||||
|  | { | ||||||
|  |     m_wallpaper_path = path; | ||||||
|  |     m_wallpaper = move(bitmap); | ||||||
|  |     invalidate(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::flip_buffers() | ||||||
|  | { | ||||||
|  |     swap(m_front_bitmap, m_back_bitmap); | ||||||
|  |     swap(m_front_painter, m_back_painter); | ||||||
|  |     int new_y_offset = m_buffers_are_flipped ? 0 : WSScreen::the().height(); | ||||||
|  |     WSScreen::the().set_y_offset(new_y_offset); | ||||||
|  |     m_buffers_are_flipped = !m_buffers_are_flipped; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::set_resolution(int width, int height) | ||||||
|  | { | ||||||
|  |     auto screen_rect = WSScreen::the().rect(); | ||||||
|  |     if (screen_rect.width() == width && screen_rect.height() == height) | ||||||
|  |         return; | ||||||
|  |     m_wallpaper_path = { }; | ||||||
|  |     m_wallpaper = nullptr; | ||||||
|  |     WSScreen::the().set_resolution(width, height); | ||||||
|  |     m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, WSScreen::the().scanline(0)); | ||||||
|  |     m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, WSScreen::the().scanline(height)); | ||||||
|  |     m_front_painter = make<Painter>(*m_front_bitmap); | ||||||
|  |     m_back_painter = make<Painter>(*m_back_bitmap); | ||||||
|  |     m_buffers_are_flipped = false; | ||||||
|  |     invalidate(); | ||||||
|  |     compose(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Rect WSCompositor::current_cursor_rect() const | ||||||
|  | { | ||||||
|  |     auto& wm = WSWindowManager::the(); | ||||||
|  |     return { WSScreen::the().cursor_location().translated(-wm.active_cursor().hotspot()), wm.active_cursor().size() }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::invalidate_cursor() | ||||||
|  | { | ||||||
|  |     invalidate(current_cursor_rect()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::draw_geometry_label() | ||||||
|  | { | ||||||
|  |     auto& wm = WSWindowManager::the(); | ||||||
|  |     auto* window_being_moved_or_resized = wm.m_drag_window ? wm.m_drag_window.ptr() : (wm.m_resize_window ? wm.m_resize_window.ptr() : nullptr); | ||||||
|  |     if (!window_being_moved_or_resized) { | ||||||
|  |         m_last_geometry_label_rect = { }; | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     auto geometry_string = window_being_moved_or_resized->rect().to_string(); | ||||||
|  |     if (!window_being_moved_or_resized->size_increment().is_null()) { | ||||||
|  |         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(); | ||||||
|  |         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(); | ||||||
|  |         geometry_string = String::format("%s (%dx%d)", geometry_string.characters(), width_steps, height_steps); | ||||||
|  |     } | ||||||
|  |     auto geometry_label_rect = Rect { 0, 0, wm.font().width(geometry_string) + 16, wm.font().glyph_height() + 10 }; | ||||||
|  |     geometry_label_rect.center_within(window_being_moved_or_resized->rect()); | ||||||
|  |     m_back_painter->fill_rect(geometry_label_rect, Color::LightGray); | ||||||
|  |     m_back_painter->draw_rect(geometry_label_rect, Color::DarkGray); | ||||||
|  |     m_back_painter->draw_text(geometry_label_rect, geometry_string, TextAlignment::Center); | ||||||
|  |     m_last_geometry_label_rect = geometry_label_rect; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::draw_cursor() | ||||||
|  | { | ||||||
|  |     auto& wm = WSWindowManager::the(); | ||||||
|  |     Rect cursor_rect = current_cursor_rect(); | ||||||
|  |     Color inner_color = Color::White; | ||||||
|  |     Color outer_color = Color::Black; | ||||||
|  |     if (WSScreen::the().mouse_button_state() & (unsigned)MouseButton::Left) | ||||||
|  |         swap(inner_color, outer_color); | ||||||
|  |     m_back_painter->blit(cursor_rect.location(), wm.active_cursor().bitmap(), wm.active_cursor().rect()); | ||||||
|  |     m_last_cursor_rect = cursor_rect; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WSCompositor::draw_menubar() | ||||||
|  | { | ||||||
|  |     auto& wm = WSWindowManager::the(); | ||||||
|  |     auto menubar_rect = wm.menubar_rect(); | ||||||
|  | 
 | ||||||
|  |     m_back_painter->fill_rect(menubar_rect, Color::LightGray); | ||||||
|  |     m_back_painter->draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, Color::MidGray); | ||||||
|  |     int index = 0; | ||||||
|  |     wm.for_each_active_menubar_menu([&] (WSMenu& menu) { | ||||||
|  |         Color text_color = Color::Black; | ||||||
|  |         if (&menu == wm.current_menu()) { | ||||||
|  |             m_back_painter->fill_rect(menu.rect_in_menubar(), wm.menu_selection_color()); | ||||||
|  |             text_color = Color::White; | ||||||
|  |         } | ||||||
|  |         m_back_painter->draw_text( | ||||||
|  |             menu.text_rect_in_menubar(), | ||||||
|  |             menu.name(), | ||||||
|  |             index == 1 ? wm.app_menu_font() : wm.menu_font(), | ||||||
|  |             TextAlignment::CenterLeft, | ||||||
|  |             text_color | ||||||
|  |         ); | ||||||
|  |         ++index; | ||||||
|  |         return true; | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     int username_width = Font::default_bold_font().width(wm.m_username); | ||||||
|  |     Rect username_rect { | ||||||
|  |         menubar_rect.right() - wm.menubar_menu_margin() / 2 - Font::default_bold_font().width(wm.m_username), | ||||||
|  |         menubar_rect.y(), | ||||||
|  |         username_width, | ||||||
|  |         menubar_rect.height() | ||||||
|  |     }; | ||||||
|  |     m_back_painter->draw_text(username_rect, wm.m_username, Font::default_bold_font(), TextAlignment::CenterRight, Color::Black); | ||||||
|  | 
 | ||||||
|  |     time_t now = time(nullptr); | ||||||
|  |     auto* tm = localtime(&now); | ||||||
|  |     auto time_text = String::format("%4u-%02u-%02u %02u:%02u:%02u", | ||||||
|  |         tm->tm_year + 1900, | ||||||
|  |         tm->tm_mon + 1, | ||||||
|  |         tm->tm_mday, | ||||||
|  |         tm->tm_hour, | ||||||
|  |         tm->tm_min, | ||||||
|  |         tm->tm_sec); | ||||||
|  |     int time_width = wm.font().width(time_text); | ||||||
|  |     Rect time_rect { | ||||||
|  |         username_rect.left() - wm.menubar_menu_margin() / 2 - time_width, | ||||||
|  |         menubar_rect.y(), | ||||||
|  |         time_width, | ||||||
|  |         menubar_rect.height() | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     m_back_painter->draw_text(time_rect, time_text, wm.font(), TextAlignment::CenterRight, Color::Black); | ||||||
|  | 
 | ||||||
|  |     Rect cpu_rect { time_rect.right() - wm.font().width(time_text) - wm.m_cpu_monitor.capacity() - 10, time_rect.y() + 1, wm.m_cpu_monitor.capacity(), time_rect.height() - 2 }; | ||||||
|  |     wm.m_cpu_monitor.paint(*m_back_painter, cpu_rect); | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								Servers/WindowServer/WSCompositor.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								Servers/WindowServer/WSCompositor.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <AK/OwnPtr.h> | ||||||
|  | #include <AK/RetainPtr.h> | ||||||
|  | #include <LibCore/CObject.h> | ||||||
|  | #include <SharedGraphics/DisjointRectSet.h> | ||||||
|  | #include <SharedGraphics/GraphicsBitmap.h> | ||||||
|  | 
 | ||||||
|  | class Painter; | ||||||
|  | class WSCursor; | ||||||
|  | 
 | ||||||
|  | class WSCompositor final : public CObject { | ||||||
|  | public: | ||||||
|  |     static WSCompositor& the(); | ||||||
|  | 
 | ||||||
|  |     void compose(); | ||||||
|  |     void invalidate(); | ||||||
|  |     void invalidate(const Rect&); | ||||||
|  | 
 | ||||||
|  |     void set_resolution(int width, int height); | ||||||
|  | 
 | ||||||
|  |     bool set_wallpaper(const String& path, Function<void(bool)>&& callback); | ||||||
|  |     String wallpaper_path() const { return m_wallpaper_path; } | ||||||
|  | 
 | ||||||
|  |     void invalidate_cursor(); | ||||||
|  |     Rect current_cursor_rect() const; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     virtual void event(CEvent&) override; | ||||||
|  |     virtual const char* class_name() const override { return "WSCompositor"; } | ||||||
|  | 
 | ||||||
|  |     WSCompositor(); | ||||||
|  |     void flip_buffers(); | ||||||
|  |     void flush(const Rect&); | ||||||
|  |     void draw_cursor(); | ||||||
|  |     void draw_geometry_label(); | ||||||
|  |     void draw_menubar(); | ||||||
|  |     void finish_setting_wallpaper(const String& path, Retained<GraphicsBitmap>&&); | ||||||
|  | 
 | ||||||
|  |     unsigned m_compose_count { 0 }; | ||||||
|  |     unsigned m_flush_count { 0 }; | ||||||
|  |     bool m_pending_compose_event { false }; | ||||||
|  |     bool m_flash_flush { false }; | ||||||
|  |     bool m_buffers_are_flipped { false }; | ||||||
|  | 
 | ||||||
|  |     RetainPtr<GraphicsBitmap> m_front_bitmap; | ||||||
|  |     RetainPtr<GraphicsBitmap> m_back_bitmap; | ||||||
|  |     OwnPtr<Painter> m_back_painter; | ||||||
|  |     OwnPtr<Painter> m_front_painter; | ||||||
|  | 
 | ||||||
|  |     DisjointRectSet m_dirty_rects; | ||||||
|  | 
 | ||||||
|  |     Rect m_last_cursor_rect; | ||||||
|  |     Rect m_last_geometry_label_rect; | ||||||
|  | 
 | ||||||
|  |     String m_wallpaper_path; | ||||||
|  |     RetainPtr<GraphicsBitmap> m_wallpaper; | ||||||
|  | }; | ||||||
|  | @ -1,11 +1,12 @@ | ||||||
| #include "WSScreen.h" | #include "WSCompositor.h" | ||||||
| #include "WSEventLoop.h" |  | ||||||
| #include "WSEvent.h" | #include "WSEvent.h" | ||||||
|  | #include "WSEventLoop.h" | ||||||
|  | #include "WSScreen.h" | ||||||
| #include "WSWindowManager.h" | #include "WSWindowManager.h" | ||||||
| #include <unistd.h> |  | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <sys/ioctl.h> | #include <sys/ioctl.h> | ||||||
| #include <sys/mman.h> | #include <sys/mman.h> | ||||||
|  | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| static WSScreen* s_the; | static WSScreen* s_the; | ||||||
| 
 | 
 | ||||||
|  | @ -86,7 +87,7 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, int dz, unsigned buttons) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (m_cursor_location != prev_location) |     if (m_cursor_location != prev_location) | ||||||
|         WSWindowManager::the().invalidate_cursor(); |         WSCompositor::the().invalidate_cursor(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSScreen::on_receive_keyboard_data(KeyEvent kernel_event) | void WSScreen::on_receive_keyboard_data(KeyEvent kernel_event) | ||||||
|  |  | ||||||
|  | @ -1,12 +1,13 @@ | ||||||
|  | #include <SharedGraphics/CharacterBitmap.h> | ||||||
|  | #include <SharedGraphics/Font.h> | ||||||
|  | #include <SharedGraphics/Painter.h> | ||||||
|  | #include <SharedGraphics/StylePainter.h> | ||||||
|  | #include <WindowServer/WSButton.h> | ||||||
|  | #include <WindowServer/WSCompositor.h> | ||||||
|  | #include <WindowServer/WSEvent.h> | ||||||
|  | #include <WindowServer/WSWindow.h> | ||||||
| #include <WindowServer/WSWindowFrame.h> | #include <WindowServer/WSWindowFrame.h> | ||||||
| #include <WindowServer/WSWindowManager.h> | #include <WindowServer/WSWindowManager.h> | ||||||
| #include <WindowServer/WSWindow.h> |  | ||||||
| #include <WindowServer/WSEvent.h> |  | ||||||
| #include <WindowServer/WSButton.h> |  | ||||||
| #include <SharedGraphics/CharacterBitmap.h> |  | ||||||
| #include <SharedGraphics/Painter.h> |  | ||||||
| #include <SharedGraphics/Font.h> |  | ||||||
| #include <SharedGraphics/StylePainter.h> |  | ||||||
| 
 | 
 | ||||||
| static const int window_titlebar_height = 19; | static const int window_titlebar_height = 19; | ||||||
| 
 | 
 | ||||||
|  | @ -294,7 +295,7 @@ void WSWindowFrame::on_mouse_event(const WSMouseEvent& event) | ||||||
|         int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3)); |         int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3)); | ||||||
|         int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3)); |         int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3)); | ||||||
|         wm.set_resize_candidate(m_window, direction_for_hot_area[hot_area_row][hot_area_column]); |         wm.set_resize_candidate(m_window, direction_for_hot_area[hot_area_row][hot_area_column]); | ||||||
|         wm.invalidate_cursor(); |         WSCompositor::the().invalidate_cursor(); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,26 +1,27 @@ | ||||||
| #include "WSWindowManager.h" | #include "WSCompositor.h" | ||||||
| #include "WSWindow.h" |  | ||||||
| #include "WSScreen.h" |  | ||||||
| #include "WSEventLoop.h" | #include "WSEventLoop.h" | ||||||
| #include <SharedGraphics/Font.h> |  | ||||||
| #include <SharedGraphics/Painter.h> |  | ||||||
| #include <SharedGraphics/CharacterBitmap.h> |  | ||||||
| #include <AK/StdLibExtras.h> |  | ||||||
| #include <AK/Vector.h> |  | ||||||
| #include <errno.h> |  | ||||||
| #include "WSMenu.h" | #include "WSMenu.h" | ||||||
| #include "WSMenuBar.h" | #include "WSMenuBar.h" | ||||||
| #include "WSMenuItem.h" | #include "WSMenuItem.h" | ||||||
|  | #include "WSScreen.h" | ||||||
|  | #include "WSWindow.h" | ||||||
|  | #include "WSWindowManager.h" | ||||||
|  | #include <AK/StdLibExtras.h> | ||||||
|  | #include <AK/Vector.h> | ||||||
|  | #include <LibCore/CTimer.h> | ||||||
|  | #include <SharedGraphics/CharacterBitmap.h> | ||||||
|  | #include <SharedGraphics/Font.h> | ||||||
|  | #include <SharedGraphics/PNGLoader.h> | ||||||
|  | #include <SharedGraphics/Painter.h> | ||||||
|  | #include <SharedGraphics/StylePainter.h> | ||||||
|  | #include <WindowServer/WSAPITypes.h> | ||||||
|  | #include <WindowServer/WSButton.h> | ||||||
| #include <WindowServer/WSClientConnection.h> | #include <WindowServer/WSClientConnection.h> | ||||||
| #include <unistd.h> | #include <WindowServer/WSCursor.h> | ||||||
|  | #include <errno.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <time.h> | #include <time.h> | ||||||
| #include <SharedGraphics/StylePainter.h> | #include <unistd.h> | ||||||
| #include <SharedGraphics/PNGLoader.h> |  | ||||||
| #include <WindowServer/WSCursor.h> |  | ||||||
| #include <WindowServer/WSButton.h> |  | ||||||
| #include <LibCore/CTimer.h> |  | ||||||
| #include <WindowServer/WSAPITypes.h> |  | ||||||
| 
 | 
 | ||||||
| //#define DEBUG_COUNTERS
 | //#define DEBUG_COUNTERS
 | ||||||
| //#define RESIZE_DEBUG
 | //#define RESIZE_DEBUG
 | ||||||
|  | @ -33,35 +34,18 @@ WSWindowManager& WSWindowManager::the() | ||||||
|     return *s_the; |     return *s_the; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::flip_buffers() |  | ||||||
| { |  | ||||||
|     swap(m_front_bitmap, m_back_bitmap); |  | ||||||
|     swap(m_front_painter, m_back_painter); |  | ||||||
|     int new_y_offset = m_buffers_are_flipped ? 0 : m_screen_rect.height(); |  | ||||||
|     WSScreen::the().set_y_offset(new_y_offset); |  | ||||||
|     m_buffers_are_flipped = !m_buffers_are_flipped; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| WSWindowManager::WSWindowManager() | WSWindowManager::WSWindowManager() | ||||||
|     : m_screen(WSScreen::the()) |  | ||||||
|     , m_screen_rect(m_screen.rect()) |  | ||||||
|     , m_flash_flush(false) |  | ||||||
| { | { | ||||||
|     s_the = this; |     s_the = this; | ||||||
| 
 | 
 | ||||||
| #ifndef DEBUG_COUNTERS |     m_arrow_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/arrow.png"), { 2, 2 }); | ||||||
|     (void)m_compose_count; |     m_resize_horizontally_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-horizontal.png")); | ||||||
|     (void)m_flush_count; |     m_resize_vertically_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-vertical.png")); | ||||||
| #endif |     m_resize_diagonally_tlbr_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-diagonal-tlbr.png")); | ||||||
|     auto size = m_screen_rect.size(); |     m_resize_diagonally_bltr_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-diagonal-bltr.png")); | ||||||
|     m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, m_screen.scanline(0)); |     m_i_beam_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/i-beam.png")); | ||||||
|     m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, m_screen.scanline(size.height())); |     m_disallowed_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/disallowed.png")); | ||||||
| 
 |     m_move_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/move.png")); | ||||||
|     m_front_painter = make<Painter>(*m_front_bitmap); |  | ||||||
|     m_back_painter = make<Painter>(*m_back_bitmap); |  | ||||||
| 
 |  | ||||||
|     m_front_painter->set_font(font()); |  | ||||||
|     m_back_painter->set_font(font()); |  | ||||||
| 
 | 
 | ||||||
|     m_background_color = Color(50, 50, 50); |     m_background_color = Color(50, 50, 50); | ||||||
|     m_active_window_border_color = Color(110, 34, 9); |     m_active_window_border_color = Color(110, 34, 9); | ||||||
|  | @ -77,18 +61,6 @@ WSWindowManager::WSWindowManager() | ||||||
|     m_highlight_window_border_color2 = Color::from_rgb(0xfabbbb); |     m_highlight_window_border_color2 = Color::from_rgb(0xfabbbb); | ||||||
|     m_highlight_window_title_color = Color::White; |     m_highlight_window_title_color = Color::White; | ||||||
| 
 | 
 | ||||||
|     m_arrow_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/arrow.png"), { 2, 2 }); |  | ||||||
|     m_resize_horizontally_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-horizontal.png")); |  | ||||||
|     m_resize_vertically_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-vertical.png")); |  | ||||||
|     m_resize_diagonally_tlbr_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-diagonal-tlbr.png")); |  | ||||||
|     m_resize_diagonally_bltr_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/resize-diagonal-bltr.png")); |  | ||||||
|     m_i_beam_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/i-beam.png")); |  | ||||||
|     m_disallowed_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/disallowed.png")); |  | ||||||
|     m_move_cursor = WSCursor::create(*GraphicsBitmap::load_from_file("/res/cursors/move.png")); |  | ||||||
| 
 |  | ||||||
|     m_wallpaper_path = "/res/wallpapers/retro.rgb"; |  | ||||||
|     m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 }); |  | ||||||
| 
 |  | ||||||
|     m_username = getlogin(); |     m_username = getlogin(); | ||||||
| 
 | 
 | ||||||
|     m_menu_selection_color = Color::from_rgb(0x84351a); |     m_menu_selection_color = Color::from_rgb(0x84351a); | ||||||
|  | @ -173,7 +145,7 @@ WSWindowManager::WSWindowManager() | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     invalidate(); |     invalidate(); | ||||||
|     compose(); |     WSCompositor::the().compose(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WSWindowManager::~WSWindowManager() | WSWindowManager::~WSWindowManager() | ||||||
|  | @ -205,72 +177,14 @@ void WSWindowManager::tick_clock() | ||||||
|     invalidate(menubar_rect()); |     invalidate(menubar_rect()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool WSWindowManager::set_wallpaper(const String& path, Function<void(bool)>&& callback) |  | ||||||
| { |  | ||||||
|     struct Context { |  | ||||||
|         String path; |  | ||||||
|         RetainPtr<GraphicsBitmap> bitmap; |  | ||||||
|         Function<void(bool)> callback; |  | ||||||
|     }; |  | ||||||
|     auto context = make<Context>(); |  | ||||||
|     context->path = path; |  | ||||||
|     context->callback = move(callback); |  | ||||||
| 
 |  | ||||||
|     int rc = create_thread([] (void* ctx) -> int { |  | ||||||
|         OwnPtr<Context> context((Context*)ctx); |  | ||||||
|         context->bitmap = load_png(context->path); |  | ||||||
|         if (!context->bitmap) { |  | ||||||
|             context->callback(false); |  | ||||||
|             exit_thread(0); |  | ||||||
|             return 0; |  | ||||||
|         } |  | ||||||
|         the().deferred_invoke([context = move(context)] (auto&) { |  | ||||||
|             the().finish_setting_wallpaper(context->path, *context->bitmap); |  | ||||||
|             context->callback(true); |  | ||||||
|         }); |  | ||||||
|         exit_thread(0); |  | ||||||
|         return 0; |  | ||||||
|     }, context.leak_ptr()); |  | ||||||
|     ASSERT(rc == 0); |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSWindowManager::finish_setting_wallpaper(const String& path, Retained<GraphicsBitmap>&& bitmap) |  | ||||||
| { |  | ||||||
|     m_wallpaper_path = path; |  | ||||||
|     m_wallpaper = move(bitmap); |  | ||||||
|     invalidate(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSWindowManager::set_resolution(int width, int height) | void WSWindowManager::set_resolution(int width, int height) | ||||||
| { | { | ||||||
|     if (m_screen_rect.width() == width && m_screen_rect.height() == height) |     WSCompositor::the().set_resolution(width, height); | ||||||
|         return; |  | ||||||
|     m_wallpaper_path = { }; |  | ||||||
|     m_wallpaper = nullptr; |  | ||||||
|     m_screen.set_resolution(width, height); |  | ||||||
|     m_screen_rect = m_screen.rect(); |  | ||||||
|     m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, m_screen.scanline(0)); |  | ||||||
|     m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, m_screen.scanline(height)); |  | ||||||
|     m_front_painter = make<Painter>(*m_front_bitmap); |  | ||||||
|     m_back_painter = make<Painter>(*m_back_bitmap); |  | ||||||
|     m_buffers_are_flipped = false; |  | ||||||
|     invalidate(); |  | ||||||
|     compose(); |  | ||||||
| 
 |  | ||||||
|     WSClientConnection::for_each_client([&] (WSClientConnection& client) { |     WSClientConnection::for_each_client([&] (WSClientConnection& client) { | ||||||
|         client.notify_about_new_screen_rect(m_screen_rect); |         client.notify_about_new_screen_rect(WSScreen::the().rect()); | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template<typename Callback> |  | ||||||
| void WSWindowManager::for_each_active_menubar_menu(Callback callback) |  | ||||||
| { |  | ||||||
|     callback(*m_system_menu); |  | ||||||
|     if (m_current_menubar) |  | ||||||
|         m_current_menubar->for_each_menu(callback); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| int WSWindowManager::menubar_menu_margin() const | int WSWindowManager::menubar_menu_margin() const | ||||||
| { | { | ||||||
|  | @ -315,8 +229,8 @@ void WSWindowManager::add_window(WSWindow& window) | ||||||
|     m_windows_in_order.append(&window); |     m_windows_in_order.append(&window); | ||||||
| 
 | 
 | ||||||
|     if (window.is_fullscreen()) { |     if (window.is_fullscreen()) { | ||||||
|         WSEventLoop::the().post_event(window, make<WSResizeEvent>(window.rect(), m_screen_rect)); |         WSEventLoop::the().post_event(window, make<WSResizeEvent>(window.rect(), WSScreen::the().rect())); | ||||||
|         window.set_rect(m_screen_rect); |         window.set_rect(WSScreen::the().rect()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     set_active_window(&window); |     set_active_window(&window); | ||||||
|  | @ -859,7 +773,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& hovere | ||||||
| void WSWindowManager::clear_resize_candidate() | void WSWindowManager::clear_resize_candidate() | ||||||
| { | { | ||||||
|     if (m_resize_candidate) |     if (m_resize_candidate) | ||||||
|         invalidate_cursor(); |         WSCompositor::the().invalidate_cursor(); | ||||||
|     m_resize_candidate = nullptr; |     m_resize_candidate = nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -915,167 +829,11 @@ bool WSWindowManager::any_opaque_window_above_this_one_contains_rect(const WSWin | ||||||
|     return found_containing_window; |     return found_containing_window; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::compose() |  | ||||||
| { |  | ||||||
|     auto dirty_rects = move(m_dirty_rects); |  | ||||||
|     dirty_rects.add(Rect::intersection(m_last_geometry_label_rect, m_screen_rect)); |  | ||||||
|     dirty_rects.add(Rect::intersection(m_last_cursor_rect, m_screen_rect)); |  | ||||||
|     dirty_rects.add(Rect::intersection(current_cursor_rect(), m_screen_rect)); |  | ||||||
| #ifdef DEBUG_COUNTERS |  | ||||||
|     dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.rects().size()); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     auto any_dirty_rect_intersects_window = [&dirty_rects] (const WSWindow& window) { |  | ||||||
|         auto window_frame_rect = window.frame().rect(); |  | ||||||
|         for (auto& dirty_rect : dirty_rects.rects()) { |  | ||||||
|             if (dirty_rect.intersects(window_frame_rect)) |  | ||||||
|                 return true; |  | ||||||
|         } |  | ||||||
|         return false; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     for (auto& dirty_rect : dirty_rects.rects()) { |  | ||||||
|         if (any_opaque_window_contains_rect(dirty_rect)) |  | ||||||
|             continue; |  | ||||||
|         if (!m_wallpaper) |  | ||||||
|             m_back_painter->fill_rect(dirty_rect, m_background_color); |  | ||||||
|         else |  | ||||||
|             m_back_painter->blit(dirty_rect.location(), *m_wallpaper, dirty_rect); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     auto compose_window = [&] (WSWindow& window) -> IterationDecision { |  | ||||||
|         if (!any_dirty_rect_intersects_window(window)) |  | ||||||
|             return IterationDecision::Continue; |  | ||||||
|         PainterStateSaver saver(*m_back_painter); |  | ||||||
|         m_back_painter->add_clip_rect(window.frame().rect()); |  | ||||||
|         RetainPtr<GraphicsBitmap> backing_store = window.backing_store(); |  | ||||||
|         for (auto& dirty_rect : dirty_rects.rects()) { |  | ||||||
|             if (any_opaque_window_above_this_one_contains_rect(window, dirty_rect)) |  | ||||||
|                 continue; |  | ||||||
|             PainterStateSaver saver(*m_back_painter); |  | ||||||
|             m_back_painter->add_clip_rect(dirty_rect); |  | ||||||
|             if (!backing_store) |  | ||||||
|                 m_back_painter->fill_rect(dirty_rect, window.background_color()); |  | ||||||
|             if (!window.is_fullscreen()) |  | ||||||
|                 window.frame().paint(*m_back_painter); |  | ||||||
|             if (!backing_store) |  | ||||||
|                 continue; |  | ||||||
|             Rect dirty_rect_in_window_coordinates = Rect::intersection(dirty_rect, window.rect()); |  | ||||||
|             if (dirty_rect_in_window_coordinates.is_empty()) |  | ||||||
|                 continue; |  | ||||||
|             dirty_rect_in_window_coordinates.move_by(-window.position()); |  | ||||||
|             auto dst = window.position(); |  | ||||||
|             dst.move_by(dirty_rect_in_window_coordinates.location()); |  | ||||||
| 
 |  | ||||||
|             m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity()); |  | ||||||
| 
 |  | ||||||
|             if (backing_store->width() < window.width()) { |  | ||||||
|                 Rect right_fill_rect { window.x() + backing_store->width(), window.y(), window.width() - backing_store->width(), window.height() }; |  | ||||||
|                 m_back_painter->fill_rect(right_fill_rect, window.background_color()); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (backing_store->height() < window.height()) { |  | ||||||
|                 Rect bottom_fill_rect { window.x(), window.y() + backing_store->height(), window.width(), window.height() - backing_store->height() }; |  | ||||||
|                 m_back_painter->fill_rect(bottom_fill_rect, window.background_color()); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return IterationDecision::Continue; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     if (auto* fullscreen_window = active_fullscreen_window()) { |  | ||||||
|         compose_window(*fullscreen_window); |  | ||||||
|     } else { |  | ||||||
|         for_each_visible_window_from_back_to_front([&] (WSWindow& window) { |  | ||||||
|             return compose_window(window); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         draw_geometry_label(); |  | ||||||
|         draw_menubar(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     draw_cursor(); |  | ||||||
| 
 |  | ||||||
|     if (m_flash_flush) { |  | ||||||
|         for (auto& rect : dirty_rects.rects()) |  | ||||||
|             m_front_painter->fill_rect(rect, Color::Yellow); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     flip_buffers(); |  | ||||||
|     for (auto& r : dirty_rects.rects()) |  | ||||||
|         flush(r); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Rect WSWindowManager::current_cursor_rect() const |  | ||||||
| { |  | ||||||
|     return { m_screen.cursor_location().translated(-active_cursor().hotspot()), active_cursor().size() }; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSWindowManager::invalidate_cursor() |  | ||||||
| { |  | ||||||
|     invalidate(current_cursor_rect()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Rect WSWindowManager::menubar_rect() const | Rect WSWindowManager::menubar_rect() const | ||||||
| { | { | ||||||
|     if (active_fullscreen_window()) |     if (active_fullscreen_window()) | ||||||
|         return { }; |         return { }; | ||||||
|     return { 0, 0, m_screen_rect.width(), 18 }; |     return { 0, 0, WSScreen::the().rect().width(), 18 }; | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSWindowManager::draw_menubar() |  | ||||||
| { |  | ||||||
|     auto menubar_rect = this->menubar_rect(); |  | ||||||
| 
 |  | ||||||
|     m_back_painter->fill_rect(menubar_rect, Color::LightGray); |  | ||||||
|     m_back_painter->draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, Color::MidGray); |  | ||||||
|     int index = 0; |  | ||||||
|     for_each_active_menubar_menu([&] (WSMenu& menu) { |  | ||||||
|         Color text_color = Color::Black; |  | ||||||
|         if (&menu == current_menu()) { |  | ||||||
|             m_back_painter->fill_rect(menu.rect_in_menubar(), menu_selection_color()); |  | ||||||
|             text_color = Color::White; |  | ||||||
|         } |  | ||||||
|         m_back_painter->draw_text( |  | ||||||
|             menu.text_rect_in_menubar(), |  | ||||||
|             menu.name(), |  | ||||||
|             index == 1 ? app_menu_font() : menu_font(), |  | ||||||
|             TextAlignment::CenterLeft, |  | ||||||
|             text_color |  | ||||||
|         ); |  | ||||||
|         ++index; |  | ||||||
|         return true; |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     int username_width = Font::default_bold_font().width(m_username); |  | ||||||
|     Rect username_rect { |  | ||||||
|         menubar_rect.right() - menubar_menu_margin() / 2 - Font::default_bold_font().width(m_username), |  | ||||||
|         menubar_rect.y(), |  | ||||||
|         username_width, |  | ||||||
|         menubar_rect.height() |  | ||||||
|     }; |  | ||||||
|     m_back_painter->draw_text(username_rect, m_username, Font::default_bold_font(), TextAlignment::CenterRight, Color::Black); |  | ||||||
| 
 |  | ||||||
|     time_t now = time(nullptr); |  | ||||||
|     auto* tm = localtime(&now); |  | ||||||
|     auto time_text = String::format("%4u-%02u-%02u %02u:%02u:%02u", |  | ||||||
|         tm->tm_year + 1900, |  | ||||||
|         tm->tm_mon + 1, |  | ||||||
|         tm->tm_mday, |  | ||||||
|         tm->tm_hour, |  | ||||||
|         tm->tm_min, |  | ||||||
|         tm->tm_sec); |  | ||||||
|     int time_width = font().width(time_text); |  | ||||||
|     Rect time_rect { |  | ||||||
|         username_rect.left() - menubar_menu_margin() / 2 - time_width, |  | ||||||
|         menubar_rect.y(), |  | ||||||
|         time_width, |  | ||||||
|         menubar_rect.height() |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     m_back_painter->draw_text(time_rect, time_text, font(), TextAlignment::CenterRight, Color::Black); |  | ||||||
| 
 |  | ||||||
|     Rect cpu_rect { time_rect.right() - font().width(time_text) - m_cpu_monitor.capacity() - 10, time_rect.y() + 1, m_cpu_monitor.capacity(), time_rect.height() - 2 }; |  | ||||||
|     m_cpu_monitor.paint(*m_back_painter, cpu_rect); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::draw_window_switcher() | void WSWindowManager::draw_window_switcher() | ||||||
|  | @ -1084,38 +842,6 @@ void WSWindowManager::draw_window_switcher() | ||||||
|         m_switcher.draw(); |         m_switcher.draw(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::draw_geometry_label() |  | ||||||
| { |  | ||||||
|     auto* window_being_moved_or_resized = m_drag_window ? m_drag_window.ptr() : (m_resize_window ? m_resize_window.ptr() : nullptr); |  | ||||||
|     if (!window_being_moved_or_resized) { |  | ||||||
|         m_last_geometry_label_rect = { }; |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     auto geometry_string = window_being_moved_or_resized->rect().to_string(); |  | ||||||
|     if (!window_being_moved_or_resized->size_increment().is_null()) { |  | ||||||
|         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(); |  | ||||||
|         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(); |  | ||||||
|         geometry_string = String::format("%s (%dx%d)", geometry_string.characters(), width_steps, height_steps); |  | ||||||
|     } |  | ||||||
|     auto geometry_label_rect = Rect { 0, 0, font().width(geometry_string) + 16, font().glyph_height() + 10 }; |  | ||||||
|     geometry_label_rect.center_within(window_being_moved_or_resized->rect()); |  | ||||||
|     m_back_painter->fill_rect(geometry_label_rect, Color::LightGray); |  | ||||||
|     m_back_painter->draw_rect(geometry_label_rect, Color::DarkGray); |  | ||||||
|     m_back_painter->draw_text(geometry_label_rect, geometry_string, TextAlignment::Center); |  | ||||||
|     m_last_geometry_label_rect = geometry_label_rect; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSWindowManager::draw_cursor() |  | ||||||
| { |  | ||||||
|     Rect cursor_rect = current_cursor_rect(); |  | ||||||
|     Color inner_color = Color::White; |  | ||||||
|     Color outer_color = Color::Black; |  | ||||||
|     if (m_screen.mouse_button_state() & (unsigned)MouseButton::Left) |  | ||||||
|         swap(inner_color, outer_color); |  | ||||||
|     m_back_painter->blit(cursor_rect.location(), active_cursor().bitmap(), active_cursor().rect()); |  | ||||||
|     m_last_cursor_rect = cursor_rect; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSWindowManager::event(CEvent& event) | void WSWindowManager::event(CEvent& event) | ||||||
| { | { | ||||||
|     if (static_cast<WSEvent&>(event).is_mouse_event()) { |     if (static_cast<WSEvent&>(event).is_mouse_event()) { | ||||||
|  | @ -1140,12 +866,6 @@ void WSWindowManager::event(CEvent& event) | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (event.type() == WSEvent::WM_DeferredCompose) { |  | ||||||
|         m_pending_compose_event = false; |  | ||||||
|         compose(); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     CObject::event(event); |     CObject::event(event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1206,28 +926,12 @@ void WSWindowManager::set_hovered_window(WSWindow* window) | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::invalidate() | void WSWindowManager::invalidate() | ||||||
| { | { | ||||||
|     m_dirty_rects.clear_with_capacity(); |     WSCompositor::the().invalidate(); | ||||||
|     invalidate(m_screen_rect); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::recompose_immediately() | void WSWindowManager::invalidate(const Rect& rect) | ||||||
| { | { | ||||||
|     m_dirty_rects.clear_with_capacity(); |     WSCompositor::the().invalidate(rect); | ||||||
|     invalidate(m_screen_rect, false); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSWindowManager::invalidate(const Rect& a_rect, bool should_schedule_compose_event) |  | ||||||
| { |  | ||||||
|     auto rect = Rect::intersection(a_rect, m_screen_rect); |  | ||||||
|     if (rect.is_empty()) |  | ||||||
|         return; |  | ||||||
| 
 |  | ||||||
|     m_dirty_rects.add(rect); |  | ||||||
| 
 |  | ||||||
|     if (should_schedule_compose_event && !m_pending_compose_event) { |  | ||||||
|         WSEventLoop::the().post_event(*this, make<WSEvent>(WSEvent::WM_DeferredCompose)); |  | ||||||
|         m_pending_compose_event = true; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::invalidate(const WSWindow& window) | void WSWindowManager::invalidate(const WSWindow& window) | ||||||
|  | @ -1249,25 +953,6 @@ void WSWindowManager::invalidate(const WSWindow& window, const Rect& rect) | ||||||
|     invalidate(inner_rect); |     invalidate(inner_rect); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WSWindowManager::flush(const Rect& a_rect) |  | ||||||
| { |  | ||||||
|     auto rect = Rect::intersection(a_rect, m_screen_rect); |  | ||||||
| 
 |  | ||||||
| #ifdef DEBUG_COUNTERS |  | ||||||
|     dbgprintf("[WM] flush #%u (%d,%d %dx%d)\n", ++m_flush_count, rect.x(), rect.y(), rect.width(), rect.height()); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     const RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x(); |  | ||||||
|     RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x(); |  | ||||||
|     size_t pitch = m_back_bitmap->pitch(); |  | ||||||
| 
 |  | ||||||
|     for (int y = 0; y < rect.height(); ++y) { |  | ||||||
|         fast_dword_copy(back_ptr, front_ptr, rect.width()); |  | ||||||
|         front_ptr = (const RGBA32*)((const byte*)front_ptr + pitch); |  | ||||||
|         back_ptr = (RGBA32*)((byte*)back_ptr + pitch); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void WSWindowManager::close_menu(WSMenu& menu) | void WSWindowManager::close_menu(WSMenu& menu) | ||||||
| { | { | ||||||
|     if (current_menu() == &menu) |     if (current_menu() == &menu) | ||||||
|  | @ -1337,7 +1022,7 @@ void WSWindowManager::set_resize_candidate(WSWindow& window, ResizeDirection dir | ||||||
| 
 | 
 | ||||||
| Rect WSWindowManager::maximized_window_rect(const WSWindow& window) const | Rect WSWindowManager::maximized_window_rect(const WSWindow& window) const | ||||||
| { | { | ||||||
|     Rect rect = m_screen_rect; |     Rect rect = WSScreen::the().rect(); | ||||||
| 
 | 
 | ||||||
|     // Subtract window title bar (leaving the border)
 |     // Subtract window title bar (leaving the border)
 | ||||||
|     rect.set_y(rect.y() + window.frame().title_bar_rect().height()); |     rect.set_y(rect.y() + window.frame().title_bar_rect().height()); | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ class WSButton; | ||||||
| enum class ResizeDirection { None, Left, UpLeft, Up, UpRight, Right, DownRight, Down, DownLeft }; | enum class ResizeDirection { None, Left, UpLeft, Up, UpRight, Right, DownRight, Down, DownLeft }; | ||||||
| 
 | 
 | ||||||
| class WSWindowManager : public CObject { | class WSWindowManager : public CObject { | ||||||
|  |     friend class WSCompositor; | ||||||
|     friend class WSWindowFrame; |     friend class WSWindowFrame; | ||||||
|     friend class WSWindowSwitcher; |     friend class WSWindowSwitcher; | ||||||
| public: | public: | ||||||
|  | @ -57,7 +58,6 @@ public: | ||||||
| 
 | 
 | ||||||
|     void move_to_front_and_make_active(WSWindow&); |     void move_to_front_and_make_active(WSWindow&); | ||||||
| 
 | 
 | ||||||
|     void invalidate_cursor(); |  | ||||||
|     void draw_cursor(); |     void draw_cursor(); | ||||||
|     void draw_menubar(); |     void draw_menubar(); | ||||||
|     void draw_window_switcher(); |     void draw_window_switcher(); | ||||||
|  | @ -69,11 +69,20 @@ public: | ||||||
|     WSMenu* current_menu() { return m_current_menu.ptr(); } |     WSMenu* current_menu() { return m_current_menu.ptr(); } | ||||||
|     void set_current_menu(WSMenu*); |     void set_current_menu(WSMenu*); | ||||||
| 
 | 
 | ||||||
|  |     const WSCursor& active_cursor() const; | ||||||
|  |     const WSCursor& arrow_cursor() const { return *m_arrow_cursor; } | ||||||
|  |     const WSCursor& resize_horizontally_cursor() const { return *m_resize_horizontally_cursor; } | ||||||
|  |     const WSCursor& resize_vertically_cursor() const { return *m_resize_vertically_cursor; } | ||||||
|  |     const WSCursor& resize_diagonally_tlbr_cursor() const { return *m_resize_diagonally_tlbr_cursor; } | ||||||
|  |     const WSCursor& resize_diagonally_bltr_cursor() const { return *m_resize_diagonally_bltr_cursor; } | ||||||
|  |     const WSCursor& i_beam_cursor() const { return *m_i_beam_cursor; } | ||||||
|  |     const WSCursor& disallowed_cursor() const { return *m_disallowed_cursor; } | ||||||
|  |     const WSCursor& move_cursor() const { return *m_move_cursor; } | ||||||
|  | 
 | ||||||
|     void invalidate(const WSWindow&); |     void invalidate(const WSWindow&); | ||||||
|     void invalidate(const WSWindow&, const Rect&); |     void invalidate(const WSWindow&, const Rect&); | ||||||
|     void invalidate(const Rect&, bool should_schedule_compose_event = true); |     void invalidate(const Rect&); | ||||||
|     void invalidate(); |     void invalidate(); | ||||||
|     void recompose_immediately(); |  | ||||||
|     void flush(const Rect&); |     void flush(const Rect&); | ||||||
| 
 | 
 | ||||||
|     const Font& font() const; |     const Font& font() const; | ||||||
|  | @ -88,21 +97,6 @@ public: | ||||||
| 
 | 
 | ||||||
|     void set_resolution(int width, int height); |     void set_resolution(int width, int height); | ||||||
| 
 | 
 | ||||||
|     bool set_wallpaper(const String& path, Function<void(bool)>&& callback); |  | ||||||
|     String wallpaper_path() const { return m_wallpaper_path; } |  | ||||||
| 
 |  | ||||||
|     const WSCursor& active_cursor() const; |  | ||||||
|     Rect current_cursor_rect() const; |  | ||||||
| 
 |  | ||||||
|     const WSCursor& arrow_cursor() const { return *m_arrow_cursor; } |  | ||||||
|     const WSCursor& resize_horizontally_cursor() const { return *m_resize_horizontally_cursor; } |  | ||||||
|     const WSCursor& resize_vertically_cursor() const { return *m_resize_vertically_cursor; } |  | ||||||
|     const WSCursor& resize_diagonally_tlbr_cursor() const { return *m_resize_diagonally_tlbr_cursor; } |  | ||||||
|     const WSCursor& resize_diagonally_bltr_cursor() const { return *m_resize_diagonally_bltr_cursor; } |  | ||||||
|     const WSCursor& i_beam_cursor() const { return *m_i_beam_cursor; } |  | ||||||
|     const WSCursor& disallowed_cursor() const { return *m_disallowed_cursor; } |  | ||||||
|     const WSCursor& move_cursor() const { return *m_move_cursor; } |  | ||||||
| 
 |  | ||||||
|     void set_active_window(WSWindow*); |     void set_active_window(WSWindow*); | ||||||
|     void set_hovered_button(WSButton*); |     void set_hovered_button(WSButton*); | ||||||
| 
 | 
 | ||||||
|  | @ -143,7 +137,15 @@ private: | ||||||
|     template<typename Callback> IterationDecision for_each_visible_window_from_back_to_front(Callback); |     template<typename Callback> IterationDecision for_each_visible_window_from_back_to_front(Callback); | ||||||
|     template<typename Callback> void for_each_window_listening_to_wm_events(Callback); |     template<typename Callback> void for_each_window_listening_to_wm_events(Callback); | ||||||
|     template<typename Callback> void for_each_window(Callback); |     template<typename Callback> void for_each_window(Callback); | ||||||
|     template<typename Callback> void for_each_active_menubar_menu(Callback); | 
 | ||||||
|  |     template<typename Callback> | ||||||
|  |     void for_each_active_menubar_menu(Callback callback) | ||||||
|  |     { | ||||||
|  |         callback(*m_system_menu); | ||||||
|  |         if (m_current_menubar) | ||||||
|  |             m_current_menubar->for_each_menu(callback); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     void close_current_menu(); |     void close_current_menu(); | ||||||
|     virtual void event(CEvent&) override; |     virtual void event(CEvent&) override; | ||||||
|     void compose(); |     void compose(); | ||||||
|  | @ -154,10 +156,15 @@ private: | ||||||
|     void tell_wm_listener_about_window_icon(WSWindow& listener, WSWindow&); |     void tell_wm_listener_about_window_icon(WSWindow& listener, WSWindow&); | ||||||
|     void tell_wm_listener_about_window_rect(WSWindow& listener, WSWindow&); |     void tell_wm_listener_about_window_rect(WSWindow& listener, WSWindow&); | ||||||
|     void pick_new_active_window(); |     void pick_new_active_window(); | ||||||
|     void finish_setting_wallpaper(const String& path, Retained<GraphicsBitmap>&&); |  | ||||||
| 
 | 
 | ||||||
|     WSScreen& m_screen; |     RetainPtr<WSCursor> m_arrow_cursor; | ||||||
|     Rect m_screen_rect; |     RetainPtr<WSCursor> m_resize_horizontally_cursor; | ||||||
|  |     RetainPtr<WSCursor> m_resize_vertically_cursor; | ||||||
|  |     RetainPtr<WSCursor> m_resize_diagonally_tlbr_cursor; | ||||||
|  |     RetainPtr<WSCursor> m_resize_diagonally_bltr_cursor; | ||||||
|  |     RetainPtr<WSCursor> m_i_beam_cursor; | ||||||
|  |     RetainPtr<WSCursor> m_disallowed_cursor; | ||||||
|  |     RetainPtr<WSCursor> m_move_cursor; | ||||||
| 
 | 
 | ||||||
|     Color m_background_color; |     Color m_background_color; | ||||||
|     Color m_active_window_border_color; |     Color m_active_window_border_color; | ||||||
|  | @ -208,37 +215,6 @@ private: | ||||||
|     Point m_resize_origin; |     Point m_resize_origin; | ||||||
|     ResizeDirection m_resize_direction { ResizeDirection::None }; |     ResizeDirection m_resize_direction { ResizeDirection::None }; | ||||||
| 
 | 
 | ||||||
|     Rect m_last_cursor_rect; |  | ||||||
|     Rect m_last_geometry_label_rect; |  | ||||||
| 
 |  | ||||||
|     unsigned m_compose_count { 0 }; |  | ||||||
|     unsigned m_flush_count { 0 }; |  | ||||||
| 
 |  | ||||||
|     RetainPtr<GraphicsBitmap> m_front_bitmap; |  | ||||||
|     RetainPtr<GraphicsBitmap> m_back_bitmap; |  | ||||||
| 
 |  | ||||||
|     DisjointRectSet m_dirty_rects; |  | ||||||
| 
 |  | ||||||
|     bool m_pending_compose_event { false }; |  | ||||||
| 
 |  | ||||||
|     RetainPtr<WSCursor> m_arrow_cursor; |  | ||||||
|     RetainPtr<WSCursor> m_resize_horizontally_cursor; |  | ||||||
|     RetainPtr<WSCursor> m_resize_vertically_cursor; |  | ||||||
|     RetainPtr<WSCursor> m_resize_diagonally_tlbr_cursor; |  | ||||||
|     RetainPtr<WSCursor> m_resize_diagonally_bltr_cursor; |  | ||||||
|     RetainPtr<WSCursor> m_i_beam_cursor; |  | ||||||
|     RetainPtr<WSCursor> m_disallowed_cursor; |  | ||||||
|     RetainPtr<WSCursor> m_move_cursor; |  | ||||||
| 
 |  | ||||||
|     OwnPtr<Painter> m_back_painter; |  | ||||||
|     OwnPtr<Painter> m_front_painter; |  | ||||||
| 
 |  | ||||||
|     String m_wallpaper_path; |  | ||||||
|     RetainPtr<GraphicsBitmap> m_wallpaper; |  | ||||||
| 
 |  | ||||||
|     bool m_flash_flush { false }; |  | ||||||
|     bool m_buffers_are_flipped { false }; |  | ||||||
| 
 |  | ||||||
|     byte m_keyboard_modifiers { 0 }; |     byte m_keyboard_modifiers { 0 }; | ||||||
| 
 | 
 | ||||||
|     OwnPtr<WSMenu> m_system_menu; |     OwnPtr<WSMenu> m_system_menu; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| #include <WindowServer/WSWindowSwitcher.h> | #include <WindowServer/WSWindowSwitcher.h> | ||||||
| #include <WindowServer/WSWindowManager.h> | #include <WindowServer/WSWindowManager.h> | ||||||
| #include <WindowServer/WSEvent.h> | #include <WindowServer/WSEvent.h> | ||||||
|  | #include <WindowServer/WSScreen.h> | ||||||
| #include <SharedGraphics/Font.h> | #include <SharedGraphics/Font.h> | ||||||
| #include <SharedGraphics/StylePainter.h> | #include <SharedGraphics/StylePainter.h> | ||||||
| 
 | 
 | ||||||
|  | @ -130,7 +131,7 @@ void WSWindowSwitcher::refresh() | ||||||
|     int space_for_window_rect = 180; |     int space_for_window_rect = 180; | ||||||
|     m_rect.set_width(thumbnail_width() + longest_title_width + space_for_window_rect + padding() * 2 + item_padding() * 2); |     m_rect.set_width(thumbnail_width() + longest_title_width + space_for_window_rect + padding() * 2 + item_padding() * 2); | ||||||
|     m_rect.set_height(window_count * item_height() + padding() * 2); |     m_rect.set_height(window_count * item_height() + padding() * 2); | ||||||
|     m_rect.center_within(wm.m_screen_rect); |     m_rect.center_within(WSScreen::the().rect()); | ||||||
|     if (!m_switcher_window) |     if (!m_switcher_window) | ||||||
|         m_switcher_window = make<WSWindow>(*this, WSWindowType::WindowSwitcher); |         m_switcher_window = make<WSWindow>(*this, WSWindowType::WindowSwitcher); | ||||||
|     m_switcher_window->set_rect(m_rect); |     m_switcher_window->set_rect(m_rect); | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| #include <WindowServer/WSScreen.h> | #include <WindowServer/WSScreen.h> | ||||||
| #include <WindowServer/WSWindowManager.h> | #include <WindowServer/WSWindowManager.h> | ||||||
| #include <WindowServer/WSEventLoop.h> | #include <WindowServer/WSEventLoop.h> | ||||||
|  | #include <WindowServer/WSCompositor.h> | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
|  | @ -18,6 +19,7 @@ int main(int, char**) | ||||||
| 
 | 
 | ||||||
|     WSEventLoop loop; |     WSEventLoop loop; | ||||||
|     WSScreen screen(1024, 768); |     WSScreen screen(1024, 768); | ||||||
|  |     WSCompositor::the(); | ||||||
|     WSWindowManager window_manager; |     WSWindowManager window_manager; | ||||||
| 
 | 
 | ||||||
|     dbgprintf("Entering WindowServer main loop.\n"); |     dbgprintf("Entering WindowServer main loop.\n"); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling