mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12:45 +00:00 
			
		
		
		
	Rework the rendering model so that clients instantiate backing stores.
This makes interactive resizing work a lot better, althought it's still not perfect. There are still glitches and unpleasant flashes of zeroed memory.
This commit is contained in:
		
							parent
							
								
									e0b81ee4c9
								
							
						
					
					
						commit
						fa02d2a39b
					
				
					 17 changed files with 185 additions and 46 deletions
				
			
		|  | @ -760,3 +760,9 @@ void Terminal::force_repaint() | ||||||
|     m_need_full_flush = true; |     m_need_full_flush = true; | ||||||
|     update(); |     update(); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void Terminal::resize_event(GResizeEvent&) | ||||||
|  | { | ||||||
|  |     m_needs_background_fill = true; | ||||||
|  |     force_repaint(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ public: | ||||||
| private: | private: | ||||||
|     virtual void event(GEvent&) override; |     virtual void event(GEvent&) override; | ||||||
|     virtual void paint_event(GPaintEvent&) override; |     virtual void paint_event(GPaintEvent&) override; | ||||||
|  |     virtual void resize_event(GResizeEvent&) override; | ||||||
|     virtual void keydown_event(GKeyEvent&) override; |     virtual void keydown_event(GKeyEvent&) override; | ||||||
|     virtual const char* class_name() const override { return "Terminal"; } |     virtual const char* class_name() const override { return "Terminal"; } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -78,8 +78,11 @@ int GEventLoop::exec() | ||||||
|     for (;;) { |     for (;;) { | ||||||
|         if (m_exit_requested) |         if (m_exit_requested) | ||||||
|             return m_exit_code; |             return m_exit_code; | ||||||
|         if (m_queued_events.is_empty()) |         process_unprocessed_messages(); | ||||||
|  |         if (m_queued_events.is_empty()) { | ||||||
|             wait_for_event(); |             wait_for_event(); | ||||||
|  |             process_unprocessed_messages(); | ||||||
|  |         } | ||||||
|         Vector<QueuedEvent> events = move(m_queued_events); |         Vector<QueuedEvent> events = move(m_queued_events); | ||||||
|         for (auto& queued_event : events) { |         for (auto& queued_event : events) { | ||||||
|             auto* receiver = queued_event.receiver; |             auto* receiver = queued_event.receiver; | ||||||
|  | @ -223,6 +226,7 @@ void GEventLoop::wait_for_event() | ||||||
|     struct timeval timeout = { 0, 0 }; |     struct timeval timeout = { 0, 0 }; | ||||||
|     if (!m_timers.is_empty()) |     if (!m_timers.is_empty()) | ||||||
|         get_next_timer_expiration(timeout); |         get_next_timer_expiration(timeout); | ||||||
|  |     ASSERT(m_unprocessed_messages.is_empty()); | ||||||
|     int rc = select(max_fd + 1, &rfds, &wfds, nullptr, (m_queued_events.is_empty() && m_timers.is_empty()) ? nullptr : &timeout); |     int rc = select(max_fd + 1, &rfds, &wfds, nullptr, (m_queued_events.is_empty() && m_timers.is_empty()) ? nullptr : &timeout); | ||||||
|     if (rc < 0) { |     if (rc < 0) { | ||||||
|         ASSERT_NOT_REACHED(); |         ASSERT_NOT_REACHED(); | ||||||
|  | @ -260,9 +264,16 @@ void GEventLoop::wait_for_event() | ||||||
| 
 | 
 | ||||||
|     bool success = drain_messages_from_server(); |     bool success = drain_messages_from_server(); | ||||||
|     ASSERT(success); |     ASSERT(success); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | void GEventLoop::process_unprocessed_messages() | ||||||
|  | { | ||||||
|     auto unprocessed_events = move(m_unprocessed_messages); |     auto unprocessed_events = move(m_unprocessed_messages); | ||||||
|     for (auto& event : unprocessed_events) { |     for (auto& event : unprocessed_events) { | ||||||
|  |         if (event.type == WSAPI_ServerMessage::Type::Greeting) { | ||||||
|  |             m_server_pid = event.greeting.server_pid; | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if (event.type == WSAPI_ServerMessage::Error) { |         if (event.type == WSAPI_ServerMessage::Error) { | ||||||
|             dbgprintf("GEventLoop got error message from server\n"); |             dbgprintf("GEventLoop got error message from server\n"); | ||||||
|  | @ -315,6 +326,9 @@ void GEventLoop::wait_for_event() | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     if (!m_unprocessed_messages.is_empty()) | ||||||
|  |         process_unprocessed_messages(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool GEventLoop::drain_messages_from_server() | bool GEventLoop::drain_messages_from_server() | ||||||
|  |  | ||||||
|  | @ -39,9 +39,12 @@ public: | ||||||
| 
 | 
 | ||||||
|     WSAPI_ServerMessage sync_request(const WSAPI_ClientMessage& request, WSAPI_ServerMessage::Type response_type); |     WSAPI_ServerMessage sync_request(const WSAPI_ClientMessage& request, WSAPI_ServerMessage::Type response_type); | ||||||
| 
 | 
 | ||||||
|  |     pid_t server_pid() const { return m_server_pid; } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     void wait_for_event(); |     void wait_for_event(); | ||||||
|     bool drain_messages_from_server(); |     bool drain_messages_from_server(); | ||||||
|  |     void process_unprocessed_messages(); | ||||||
|     void handle_paint_event(const WSAPI_ServerMessage&, GWindow&); |     void handle_paint_event(const WSAPI_ServerMessage&, GWindow&); | ||||||
|     void handle_resize_event(const WSAPI_ServerMessage&, GWindow&); |     void handle_resize_event(const WSAPI_ServerMessage&, GWindow&); | ||||||
|     void handle_mouse_event(const WSAPI_ServerMessage&, GWindow&); |     void handle_mouse_event(const WSAPI_ServerMessage&, GWindow&); | ||||||
|  | @ -64,8 +67,8 @@ private: | ||||||
|     bool m_running { false }; |     bool m_running { false }; | ||||||
|     bool m_exit_requested { false }; |     bool m_exit_requested { false }; | ||||||
|     int m_exit_code { 0 }; |     int m_exit_code { 0 }; | ||||||
| 
 |  | ||||||
|     int m_next_timer_id { 1 }; |     int m_next_timer_id { 1 }; | ||||||
|  |     pid_t m_server_pid { 0 }; | ||||||
| 
 | 
 | ||||||
|     struct EventLoopTimer { |     struct EventLoopTimer { | ||||||
|         int timer_id { 0 }; |         int timer_id { 0 }; | ||||||
|  |  | ||||||
|  | @ -28,11 +28,14 @@ void GWidget::set_relative_rect(const Rect& rect) | ||||||
| { | { | ||||||
|     if (rect == m_relative_rect) |     if (rect == m_relative_rect) | ||||||
|         return; |         return; | ||||||
|     if (m_relative_rect.size() != rect.size()) { |     bool size_changed = m_relative_rect.size() != rect.size(); | ||||||
|         auto event = make<GResizeEvent>(m_relative_rect.size(), rect.size()); |  | ||||||
|         GEventLoop::main().post_event(this, move(event)); |  | ||||||
|     } |  | ||||||
|     m_relative_rect = rect; |     m_relative_rect = rect; | ||||||
|  | 
 | ||||||
|  |     if (size_changed) { | ||||||
|  |         GResizeEvent resize_event(m_relative_rect.size(), rect.size()); | ||||||
|  |         event(resize_event); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     update(); |     update(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -169,9 +169,36 @@ void GWindow::event(GEvent& event) | ||||||
|             return; |             return; | ||||||
|         auto& paint_event = static_cast<GPaintEvent&>(event); |         auto& paint_event = static_cast<GPaintEvent&>(event); | ||||||
|         auto rect = paint_event.rect(); |         auto rect = paint_event.rect(); | ||||||
|         if (rect.is_empty()) |         bool created_new_backing_store = !m_backing; | ||||||
|  |         if (!m_backing) { | ||||||
|  |             // NOTE: size() may change at any time since it's synchronously retrieved from the WindowServer.
 | ||||||
|  |             ASSERT(GEventLoop::main().server_pid()); | ||||||
|  |             Size new_backing_store_size = size(); | ||||||
|  |             size_t size_in_bytes = new_backing_store_size.area() * sizeof(RGBA32); | ||||||
|  |             void* buffer; | ||||||
|  |             int shared_buffer_id = create_shared_buffer(GEventLoop::main().server_pid(), size_in_bytes, (void**)&buffer); | ||||||
|  |             ASSERT(shared_buffer_id >= 0); | ||||||
|  |             ASSERT(buffer); | ||||||
|  |             ASSERT(buffer != (void*)-1); | ||||||
|  |             m_backing = GraphicsBitmap::create_with_shared_buffer( | ||||||
|  |                         m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32, | ||||||
|  |                         shared_buffer_id, | ||||||
|  |                         new_backing_store_size, (RGBA32*)buffer); | ||||||
|  |         } | ||||||
|  |         if (rect.is_empty() || created_new_backing_store) | ||||||
|             rect = m_main_widget->rect(); |             rect = m_main_widget->rect(); | ||||||
|         m_main_widget->event(*make<GPaintEvent>(rect)); |         m_main_widget->event(*make<GPaintEvent>(rect)); | ||||||
|  |         if (created_new_backing_store) { | ||||||
|  |             WSAPI_ClientMessage message; | ||||||
|  |             message.type = WSAPI_ClientMessage::Type::SetWindowBackingStore; | ||||||
|  |             message.window_id = m_window_id; | ||||||
|  |             message.backing.bpp = 32; | ||||||
|  |             message.backing.pitch = m_backing->pitch(); | ||||||
|  |             message.backing.shared_buffer_id = m_backing->shared_buffer_id(); | ||||||
|  |             message.backing.has_alpha_channel = m_backing->has_alpha_channel(); | ||||||
|  |             message.backing.size = m_backing->size(); | ||||||
|  |             GEventLoop::main().post_message_to_server(message); | ||||||
|  |         } | ||||||
|         if (m_window_id) { |         if (m_window_id) { | ||||||
|             WSAPI_ClientMessage message; |             WSAPI_ClientMessage message; | ||||||
|             message.type = WSAPI_ClientMessage::Type::DidFinishPainting; |             message.type = WSAPI_ClientMessage::Type::DidFinishPainting; | ||||||
|  | @ -210,6 +237,7 @@ void GWindow::event(GEvent& event) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (event.type() == GEvent::Resize) { |     if (event.type() == GEvent::Resize) { | ||||||
|  |         m_backing = nullptr; | ||||||
|         m_pending_paint_event_rects.clear(); |         m_pending_paint_event_rects.clear(); | ||||||
|         m_rect_when_windowless = { { }, static_cast<GResizeEvent&>(event).size() }; |         m_rect_when_windowless = { { }, static_cast<GResizeEvent&>(event).size() }; | ||||||
|         m_main_widget->set_relative_rect({ { }, static_cast<GResizeEvent&>(event).size() }); |         m_main_widget->set_relative_rect({ { }, static_cast<GResizeEvent&>(event).size() }); | ||||||
|  | @ -233,7 +261,7 @@ void GWindow::update(const Rect& a_rect) | ||||||
| #ifdef UPDATE_COALESCING_DEBUG | #ifdef UPDATE_COALESCING_DEBUG | ||||||
|             dbgprintf("Ignoring %s since it's contained by pending rect %s\n", a_rect.to_string().characters(), pending_rect.to_string().characters()); |             dbgprintf("Ignoring %s since it's contained by pending rect %s\n", a_rect.to_string().characters(), pending_rect.to_string().characters()); | ||||||
| #endif | #endif | ||||||
|             return; |             //return;
 | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     m_pending_paint_event_rects.append(a_rect); |     m_pending_paint_event_rects.append(a_rect); | ||||||
|  |  | ||||||
|  | @ -68,6 +68,8 @@ public: | ||||||
|     const GWidget* hovered_widget() const { return m_hovered_widget.ptr(); } |     const GWidget* hovered_widget() const { return m_hovered_widget.ptr(); } | ||||||
|     void set_hovered_widget(GWidget*); |     void set_hovered_widget(GWidget*); | ||||||
| 
 | 
 | ||||||
|  |     GraphicsBitmap* backing() { return m_backing.ptr(); } | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     virtual const char* class_name() const override { return "GWindow"; } |     virtual const char* class_name() const override { return "GWindow"; } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,17 +25,9 @@ Painter::Painter(GraphicsBitmap& bitmap) | ||||||
| Painter::Painter(GWidget& widget) | Painter::Painter(GWidget& widget) | ||||||
|     : m_font(&widget.font()) |     : m_font(&widget.font()) | ||||||
| { | { | ||||||
|     WSAPI_ClientMessage request; |  | ||||||
|     request.type = WSAPI_ClientMessage::Type::GetWindowBackingStore; |  | ||||||
|     request.window_id = widget.window()->window_id(); |  | ||||||
|     auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::DidGetWindowBackingStore); |  | ||||||
| 
 |  | ||||||
|     m_target = GraphicsBitmap::create_with_shared_buffer( |  | ||||||
|                    response.backing.has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32, |  | ||||||
|                    response.backing.shared_buffer_id, |  | ||||||
|                    response.backing.size); |  | ||||||
|     ASSERT(m_target); |  | ||||||
|     m_window = widget.window(); |     m_window = widget.window(); | ||||||
|  |     m_target = m_window->backing(); | ||||||
|  |     ASSERT(m_target); | ||||||
|     m_translation.move_by(widget.window_relative_rect().location()); |     m_translation.move_by(widget.window_relative_rect().location()); | ||||||
|     // NOTE: m_clip_rect is in Window coordinates since we are painting into its backing store.
 |     // NOTE: m_clip_rect is in Window coordinates since we are painting into its backing store.
 | ||||||
|     m_clip_rect = widget.window_relative_rect(); |     m_clip_rect = widget.window_relative_rect(); | ||||||
|  | @ -236,7 +228,8 @@ void Painter::blit_with_opacity(const Point& position, const GraphicsBitmap& sou | ||||||
| 
 | 
 | ||||||
|     byte alpha = 255 * opacity; |     byte alpha = 255 * opacity; | ||||||
| 
 | 
 | ||||||
|     Rect dst_rect(position, src_rect.size()); |     Rect safe_src_rect = Rect::intersection(src_rect, source.rect()); | ||||||
|  |     Rect dst_rect(position, safe_src_rect.size()); | ||||||
|     dst_rect.move_by(m_translation); |     dst_rect.move_by(m_translation); | ||||||
|     auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); |     auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); | ||||||
|     if (clipped_rect.is_empty()) |     if (clipped_rect.is_empty()) | ||||||
|  | @ -265,7 +258,8 @@ void Painter::blit_with_opacity(const Point& position, const GraphicsBitmap& sou | ||||||
| void Painter::blit_with_alpha(const Point& position, const GraphicsBitmap& source, const Rect& src_rect) | void Painter::blit_with_alpha(const Point& position, const GraphicsBitmap& source, const Rect& src_rect) | ||||||
| { | { | ||||||
|     ASSERT(source.has_alpha_channel()); |     ASSERT(source.has_alpha_channel()); | ||||||
|     Rect dst_rect(position, src_rect.size()); |     Rect safe_src_rect = Rect::intersection(src_rect, source.rect()); | ||||||
|  |     Rect dst_rect(position, safe_src_rect.size()); | ||||||
|     dst_rect.move_by(m_translation); |     dst_rect.move_by(m_translation); | ||||||
|     auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); |     auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); | ||||||
|     if (clipped_rect.is_empty()) |     if (clipped_rect.is_empty()) | ||||||
|  | @ -298,7 +292,9 @@ void Painter::blit(const Point& position, const GraphicsBitmap& source, const Re | ||||||
| { | { | ||||||
|     if (source.has_alpha_channel()) |     if (source.has_alpha_channel()) | ||||||
|         return blit_with_alpha(position, source, src_rect); |         return blit_with_alpha(position, source, src_rect); | ||||||
|     Rect dst_rect(position, src_rect.size()); |     auto safe_src_rect = Rect::intersection(src_rect, source.rect()); | ||||||
|  |     ASSERT(source.rect().contains(safe_src_rect)); | ||||||
|  |     Rect dst_rect(position, safe_src_rect.size()); | ||||||
|     dst_rect.move_by(m_translation); |     dst_rect.move_by(m_translation); | ||||||
|     auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); |     auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); | ||||||
|     if (clipped_rect.is_empty()) |     if (clipped_rect.is_empty()) | ||||||
|  |  | ||||||
|  | @ -84,6 +84,7 @@ struct WSAPI_ServerMessage { | ||||||
|         DidGetWindowTitle, |         DidGetWindowTitle, | ||||||
|         DidGetWindowRect, |         DidGetWindowRect, | ||||||
|         DidGetWindowBackingStore, |         DidGetWindowBackingStore, | ||||||
|  |         Greeting, | ||||||
|     }; |     }; | ||||||
|     Type type { Invalid }; |     Type type { Invalid }; | ||||||
|     int window_id { -1 }; |     int window_id { -1 }; | ||||||
|  | @ -91,6 +92,9 @@ struct WSAPI_ServerMessage { | ||||||
|     char text[256]; |     char text[256]; | ||||||
| 
 | 
 | ||||||
|     union { |     union { | ||||||
|  |         struct { | ||||||
|  |             int server_pid; | ||||||
|  |         } greeting; | ||||||
|         struct { |         struct { | ||||||
|             WSAPI_Rect rect; |             WSAPI_Rect rect; | ||||||
|             WSAPI_Rect old_rect; |             WSAPI_Rect old_rect; | ||||||
|  | @ -148,6 +152,7 @@ struct WSAPI_ClientMessage { | ||||||
|         GetWindowBackingStore, |         GetWindowBackingStore, | ||||||
|         SetGlobalCursorTracking, |         SetGlobalCursorTracking, | ||||||
|         SetWindowOpacity, |         SetWindowOpacity, | ||||||
|  |         SetWindowBackingStore, | ||||||
|     }; |     }; | ||||||
|     Type type { Invalid }; |     Type type { Invalid }; | ||||||
|     int window_id { -1 }; |     int window_id { -1 }; | ||||||
|  | @ -166,6 +171,13 @@ struct WSAPI_ClientMessage { | ||||||
|             bool has_alpha_channel; |             bool has_alpha_channel; | ||||||
|             float opacity; |             float opacity; | ||||||
|         } window; |         } window; | ||||||
|  |         struct { | ||||||
|  |             WSAPI_Size size; | ||||||
|  |             size_t bpp; | ||||||
|  |             size_t pitch; | ||||||
|  |             int shared_buffer_id; | ||||||
|  |             bool has_alpha_channel; | ||||||
|  |         } backing; | ||||||
|     }; |     }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,11 @@ WSClientConnection::WSClientConnection(int fd) | ||||||
|     if (!s_connections) |     if (!s_connections) | ||||||
|         s_connections = new HashMap<int, WSClientConnection*>; |         s_connections = new HashMap<int, WSClientConnection*>; | ||||||
|     s_connections->set(m_client_id, this); |     s_connections->set(m_client_id, this); | ||||||
|  | 
 | ||||||
|  |     WSAPI_ServerMessage message; | ||||||
|  |     message.type = WSAPI_ServerMessage::Type::Greeting; | ||||||
|  |     message.greeting.server_pid = getpid(); | ||||||
|  |     post_message(message); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| WSClientConnection::~WSClientConnection() | WSClientConnection::~WSClientConnection() | ||||||
|  | @ -358,7 +363,13 @@ void WSClientConnection::handle_request(WSAPIDidFinishPaintingNotification& requ | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     auto& window = *(*it).value; |     auto& window = *(*it).value; | ||||||
|     window.set_has_painted_since_last_resize(true); | 
 | ||||||
|  |     if (!window.has_painted_since_last_resize()) { | ||||||
|  |         if (window.last_lazy_resize_rect().size() == request.rect().size()) { | ||||||
|  |             window.set_has_painted_since_last_resize(true); | ||||||
|  |             WSMessageLoop::the().post_message(&window, make<WSResizeEvent>(window.last_lazy_resize_rect(), window.rect())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     WSWindowManager::the().invalidate(window, request.rect()); |     WSWindowManager::the().invalidate(window, request.rect()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -371,7 +382,7 @@ void WSClientConnection::handle_request(WSAPIGetWindowBackingStoreRequest& reque | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     auto& window = *(*it).value; |     auto& window = *(*it).value; | ||||||
|     auto* backing_store = window.backing(); |     auto* backing_store = window.backing_store(); | ||||||
| 
 | 
 | ||||||
|     WSAPI_ServerMessage response; |     WSAPI_ServerMessage response; | ||||||
|     response.type = WSAPI_ServerMessage::Type::DidGetWindowBackingStore; |     response.type = WSAPI_ServerMessage::Type::DidGetWindowBackingStore; | ||||||
|  | @ -384,6 +395,25 @@ void WSClientConnection::handle_request(WSAPIGetWindowBackingStoreRequest& reque | ||||||
|     post_message(response); |     post_message(response); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void WSClientConnection::handle_request(WSAPISetWindowBackingStoreRequest& request) | ||||||
|  | { | ||||||
|  |     int window_id = request.window_id(); | ||||||
|  |     auto it = m_windows.find(window_id); | ||||||
|  |     if (it == m_windows.end()) { | ||||||
|  |         post_error("Bad window ID"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     auto& window = *(*it).value; | ||||||
|  |     auto backing_store = GraphicsBitmap::create_with_shared_buffer( | ||||||
|  |         request.has_alpha_channel() ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32, | ||||||
|  |         request.shared_buffer_id(), | ||||||
|  |         request.size()); | ||||||
|  |     if (!backing_store) | ||||||
|  |         return; | ||||||
|  |     window.set_backing_store(move(backing_store)); | ||||||
|  |     window.invalidate(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& request) | void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& request) | ||||||
| { | { | ||||||
|     int window_id = request.window_id(); |     int window_id = request.window_id(); | ||||||
|  | @ -437,6 +467,8 @@ void WSClientConnection::on_request(WSAPIClientRequest& request) | ||||||
|         return handle_request(static_cast<WSAPISetGlobalCursorTrackingRequest&>(request)); |         return handle_request(static_cast<WSAPISetGlobalCursorTrackingRequest&>(request)); | ||||||
|     case WSMessage::APISetWindowOpacityRequest: |     case WSMessage::APISetWindowOpacityRequest: | ||||||
|         return handle_request(static_cast<WSAPISetWindowOpacityRequest&>(request)); |         return handle_request(static_cast<WSAPISetWindowOpacityRequest&>(request)); | ||||||
|  |     case WSMessage::APISetWindowBackingStoreRequest: | ||||||
|  |         return handle_request(static_cast<WSAPISetWindowBackingStoreRequest&>(request)); | ||||||
|     default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -51,6 +51,7 @@ private: | ||||||
|     void handle_request(WSAPIInvalidateRectRequest&); |     void handle_request(WSAPIInvalidateRectRequest&); | ||||||
|     void handle_request(WSAPIDidFinishPaintingNotification&); |     void handle_request(WSAPIDidFinishPaintingNotification&); | ||||||
|     void handle_request(WSAPIGetWindowBackingStoreRequest&); |     void handle_request(WSAPIGetWindowBackingStoreRequest&); | ||||||
|  |     void handle_request(WSAPISetWindowBackingStoreRequest&); | ||||||
|     void handle_request(WSAPISetGlobalCursorTrackingRequest&); |     void handle_request(WSAPISetGlobalCursorTrackingRequest&); | ||||||
|     void handle_request(WSAPISetWindowOpacityRequest&); |     void handle_request(WSAPISetWindowOpacityRequest&); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -76,8 +76,8 @@ WSWindow& WSMenu::ensure_menu_window() | ||||||
| void WSMenu::draw() | void WSMenu::draw() | ||||||
| { | { | ||||||
|     ASSERT(menu_window()); |     ASSERT(menu_window()); | ||||||
|     ASSERT(menu_window()->backing()); |     ASSERT(menu_window()->backing_store()); | ||||||
|     Painter painter(*menu_window()->backing()); |     Painter painter(*menu_window()->backing_store()); | ||||||
| 
 | 
 | ||||||
|     Rect rect { { }, menu_window()->size() }; |     Rect rect { { }, menu_window()->size() }; | ||||||
|     painter.draw_rect(rect, Color::White); |     painter.draw_rect(rect, Color::White); | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ public: | ||||||
|         APIGetWindowBackingStoreRequest, |         APIGetWindowBackingStoreRequest, | ||||||
|         APISetGlobalCursorTrackingRequest, |         APISetGlobalCursorTrackingRequest, | ||||||
|         APISetWindowOpacityRequest, |         APISetWindowOpacityRequest, | ||||||
|  |         APISetWindowBackingStoreRequest, | ||||||
|         __End_API_Client_Requests, |         __End_API_Client_Requests, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | @ -277,6 +278,38 @@ private: | ||||||
|     float m_opacity { 0 }; |     float m_opacity { 0 }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | class WSAPISetWindowBackingStoreRequest final : public WSAPIClientRequest { | ||||||
|  | public: | ||||||
|  |     explicit WSAPISetWindowBackingStoreRequest(int client_id, int window_id, int shared_buffer_id, const Size& size, size_t bpp, size_t pitch, bool has_alpha_channel) | ||||||
|  |         : WSAPIClientRequest(WSMessage::APISetWindowBackingStoreRequest, client_id) | ||||||
|  |         , m_client_id(client_id) | ||||||
|  |         , m_window_id(window_id) | ||||||
|  |         , m_shared_buffer_id(shared_buffer_id) | ||||||
|  |         , m_size(size) | ||||||
|  |         , m_bpp(bpp) | ||||||
|  |         , m_pitch(pitch) | ||||||
|  |         , m_has_alpha_channel(has_alpha_channel) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int client_id() const { return m_client_id; } | ||||||
|  |     int window_id() const { return m_window_id; } | ||||||
|  |     int shared_buffer_id() const { return m_shared_buffer_id; } | ||||||
|  |     Size size() const { return m_size; } | ||||||
|  |     size_t bpp() const { return m_bpp; } | ||||||
|  |     size_t pitch() const { return m_pitch; } | ||||||
|  |     bool has_alpha_channel() const { return m_has_alpha_channel; } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     int m_client_id { 0 }; | ||||||
|  |     int m_window_id { 0 }; | ||||||
|  |     int m_shared_buffer_id { 0 }; | ||||||
|  |     Size m_size; | ||||||
|  |     size_t m_bpp; | ||||||
|  |     size_t m_pitch; | ||||||
|  |     bool m_has_alpha_channel; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class WSAPISetWindowRectRequest final : public WSAPIClientRequest { | class WSAPISetWindowRectRequest final : public WSAPIClientRequest { | ||||||
| public: | public: | ||||||
|     explicit WSAPISetWindowRectRequest(int client_id, int window_id, const Rect& rect) |     explicit WSAPISetWindowRectRequest(int client_id, int window_id, const Rect& rect) | ||||||
|  |  | ||||||
|  | @ -330,6 +330,9 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess | ||||||
|     case WSAPI_ClientMessage::Type::GetWindowBackingStore: |     case WSAPI_ClientMessage::Type::GetWindowBackingStore: | ||||||
|         post_message(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id)); |         post_message(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id)); | ||||||
|         break; |         break; | ||||||
|  |     case WSAPI_ClientMessage::Type::SetWindowBackingStore: | ||||||
|  |         post_message(client, make<WSAPISetWindowBackingStoreRequest>(client_id, message.window_id, message.backing.shared_buffer_id, message.backing.size, message.backing.bpp, message.backing.pitch, message.backing.has_alpha_channel)); | ||||||
|  |         break; | ||||||
|     case WSAPI_ClientMessage::Type::SetGlobalCursorTracking: |     case WSAPI_ClientMessage::Type::SetGlobalCursorTracking: | ||||||
|         post_message(client, make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.window_id, message.value)); |         post_message(client, make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.window_id, message.value)); | ||||||
|         break; |         break; | ||||||
|  |  | ||||||
|  | @ -36,18 +36,13 @@ void WSWindow::set_title(String&& title) | ||||||
| void WSWindow::set_rect(const Rect& rect) | void WSWindow::set_rect(const Rect& rect) | ||||||
| { | { | ||||||
|     Rect old_rect; |     Rect old_rect; | ||||||
|     if (!m_client && !m_menu) |     ASSERT(m_client || m_menu); | ||||||
|         return; |  | ||||||
|     if (m_rect == rect) |     if (m_rect == rect) | ||||||
|         return; |         return; | ||||||
|     old_rect = m_rect; |     old_rect = m_rect; | ||||||
|     m_rect = rect; |     m_rect = rect; | ||||||
|     if (!m_backing || old_rect.size() != rect.size()) { |     if (m_menu && (!m_backing_store || old_rect.size() != rect.size())) { | ||||||
|         if (m_menu) |         m_backing_store = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, m_rect.size()); | ||||||
|             m_backing = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, m_rect.size()); |  | ||||||
|         else if (m_client) { |  | ||||||
|             m_backing = m_client->create_shared_bitmap(m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32, m_rect.size()); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     WSWindowManager::the().notify_rect_changed(*this, old_rect, rect); |     WSWindowManager::the().notify_rect_changed(*this, old_rect, rect); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -55,7 +55,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     virtual void on_message(WSMessage&) override; |     virtual void on_message(WSMessage&) override; | ||||||
| 
 | 
 | ||||||
|     GraphicsBitmap* backing() { return m_backing.ptr(); } |     GraphicsBitmap* backing_store() { return m_backing_store.ptr(); } | ||||||
|  |     void set_backing_store(RetainPtr<GraphicsBitmap>&& backing_store) { m_backing_store = move(backing_store); } | ||||||
| 
 | 
 | ||||||
|     void set_global_cursor_tracking_enabled(bool); |     void set_global_cursor_tracking_enabled(bool); | ||||||
|     bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; } |     bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; } | ||||||
|  | @ -63,8 +64,11 @@ public: | ||||||
|     bool has_alpha_channel() const { return m_has_alpha_channel; } |     bool has_alpha_channel() const { return m_has_alpha_channel; } | ||||||
|     void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; } |     void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; } | ||||||
| 
 | 
 | ||||||
|     void set_has_painted_since_last_resize(bool b) { m_has_painted_since_last_resize = b; } |     void set_last_lazy_resize_rect(const Rect& rect) { m_last_lazy_resize_rect = rect; } | ||||||
|  |     Rect last_lazy_resize_rect() const { return m_last_lazy_resize_rect; } | ||||||
|  | 
 | ||||||
|     bool has_painted_since_last_resize() const { return m_has_painted_since_last_resize; } |     bool has_painted_since_last_resize() const { return m_has_painted_since_last_resize; } | ||||||
|  |     void set_has_painted_since_last_resize(bool b) { m_has_painted_since_last_resize = b; } | ||||||
| 
 | 
 | ||||||
|     // For InlineLinkedList.
 |     // For InlineLinkedList.
 | ||||||
|     // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
 |     // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
 | ||||||
|  | @ -81,7 +85,8 @@ private: | ||||||
|     bool m_has_alpha_channel { false }; |     bool m_has_alpha_channel { false }; | ||||||
|     bool m_has_painted_since_last_resize { false }; |     bool m_has_painted_since_last_resize { false }; | ||||||
|     WSMenu* m_menu { nullptr }; |     WSMenu* m_menu { nullptr }; | ||||||
|     RetainPtr<GraphicsBitmap> m_backing; |     RetainPtr<GraphicsBitmap> m_backing_store; | ||||||
|     int m_window_id { -1 }; |     int m_window_id { -1 }; | ||||||
|     float m_opacity { 1 }; |     float m_opacity { 1 }; | ||||||
|  |     Rect m_last_lazy_resize_rect; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ | ||||||
| //#define DEBUG_COUNTERS
 | //#define DEBUG_COUNTERS
 | ||||||
| //#define DEBUG_WID_IN_TITLE_BAR
 | //#define DEBUG_WID_IN_TITLE_BAR
 | ||||||
| #define RESIZE_DEBUG | #define RESIZE_DEBUG | ||||||
|  | #define USE_WALLPAPER | ||||||
| 
 | 
 | ||||||
| static const int window_titlebar_height = 16; | static const int window_titlebar_height = 16; | ||||||
| 
 | 
 | ||||||
|  | @ -175,8 +176,10 @@ WSWindowManager::WSWindowManager() | ||||||
|     m_cursor_bitmap_inner = CharacterBitmap::create_from_ascii(cursor_bitmap_inner_ascii, 12, 17); |     m_cursor_bitmap_inner = CharacterBitmap::create_from_ascii(cursor_bitmap_inner_ascii, 12, 17); | ||||||
|     m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17); |     m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17); | ||||||
| 
 | 
 | ||||||
|  | #ifdef USE_WALLPAPER | ||||||
|     m_wallpaper_path = "/res/wallpapers/cool.rgb"; |     m_wallpaper_path = "/res/wallpapers/cool.rgb"; | ||||||
|     m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 }); |     m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 }); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef KERNEL | #ifdef KERNEL | ||||||
|     ProcFS::the().add_sys_bool("wm_flash_flush", m_flash_flush); |     ProcFS::the().add_sys_bool("wm_flash_flush", m_flash_flush); | ||||||
|  | @ -495,6 +498,7 @@ void WSWindowManager::start_window_resize(WSWindow& window, WSMouseEvent& event) | ||||||
|     m_resize_window = window.make_weak_ptr();; |     m_resize_window = window.make_weak_ptr();; | ||||||
|     m_resize_origin = event.position(); |     m_resize_origin = event.position(); | ||||||
|     m_resize_window_original_rect = window.rect(); |     m_resize_window_original_rect = window.rect(); | ||||||
|  |     m_resize_window->set_has_painted_since_last_resize(true); | ||||||
|     invalidate(window); |     invalidate(window); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -532,6 +536,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& event_ | ||||||
|             printf("[WM] Finish resizing WSWindow{%p}\n", m_resize_window.ptr()); |             printf("[WM] Finish resizing WSWindow{%p}\n", m_resize_window.ptr()); | ||||||
| #endif | #endif | ||||||
|             WSMessageLoop::the().post_message(m_resize_window.ptr(), make<WSResizeEvent>(m_resize_window->rect(), m_resize_window->rect())); |             WSMessageLoop::the().post_message(m_resize_window.ptr(), make<WSResizeEvent>(m_resize_window->rect(), m_resize_window->rect())); | ||||||
|  |             invalidate(*m_resize_window); | ||||||
|             m_resize_window = nullptr; |             m_resize_window = nullptr; | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  | @ -541,20 +546,20 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& event_ | ||||||
|             int dx = event.x() - m_resize_origin.x(); |             int dx = event.x() - m_resize_origin.x(); | ||||||
|             int dy = event.y() - m_resize_origin.y(); |             int dy = event.y() - m_resize_origin.y(); | ||||||
|             auto new_rect = m_resize_window_original_rect; |             auto new_rect = m_resize_window_original_rect; | ||||||
|             new_rect.set_width(new_rect.width() + dx); |             new_rect.set_width(max(50, new_rect.width() + dx)); | ||||||
|             new_rect.set_height(new_rect.height() + dy); |             new_rect.set_height(max(50, new_rect.height() + dy)); | ||||||
|  |             if (m_resize_window->rect() == new_rect) | ||||||
|  |                 return; | ||||||
| #ifdef RESIZE_DEBUG | #ifdef RESIZE_DEBUG | ||||||
|             dbgprintf("[WM] Resizing [original: %s] now: %s\n", |             dbgprintf("[WM] Resizing [original: %s] now: %s\n", | ||||||
|                 m_resize_window_original_rect.to_string().characters(), |                 m_resize_window_original_rect.to_string().characters(), | ||||||
|                 new_rect.to_string().characters()); |                 new_rect.to_string().characters()); | ||||||
| #endif | #endif | ||||||
|             if (new_rect.width() < 50) |  | ||||||
|                 new_rect.set_width(50); |  | ||||||
|             if (new_rect.height() < 50) |  | ||||||
|                 new_rect.set_height(50); |  | ||||||
|             m_resize_window->set_rect(new_rect); |             m_resize_window->set_rect(new_rect); | ||||||
|             if (m_resize_window->has_painted_since_last_resize()) { |             if (m_resize_window->has_painted_since_last_resize()) { | ||||||
|                 m_resize_window->set_has_painted_since_last_resize(false); |                 m_resize_window->set_has_painted_since_last_resize(false); | ||||||
|  |                 dbgprintf("I'm gonna wait for %s\n", new_rect.to_string().characters()); | ||||||
|  |                 m_resize_window->set_last_lazy_resize_rect(new_rect); | ||||||
|                 WSMessageLoop::the().post_message(m_resize_window.ptr(), make<WSResizeEvent>(old_rect, new_rect)); |                 WSMessageLoop::the().post_message(m_resize_window.ptr(), make<WSResizeEvent>(old_rect, new_rect)); | ||||||
|             } |             } | ||||||
|             return; |             return; | ||||||
|  | @ -709,8 +714,8 @@ void WSWindowManager::compose() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for_each_visible_window_from_back_to_front([&] (WSWindow& window) { |     for_each_visible_window_from_back_to_front([&] (WSWindow& window) { | ||||||
|         RetainPtr<GraphicsBitmap> backing = window.backing(); |         RetainPtr<GraphicsBitmap> backing_store = window.backing_store(); | ||||||
|         if (!backing) |         if (!backing_store) | ||||||
|             return IterationDecision::Continue; |             return IterationDecision::Continue; | ||||||
|         if (!any_dirty_rect_intersects_window(window)) |         if (!any_dirty_rect_intersects_window(window)) | ||||||
|             return IterationDecision::Continue; |             return IterationDecision::Continue; | ||||||
|  | @ -725,9 +730,9 @@ void WSWindowManager::compose() | ||||||
|             auto dst = window.position(); |             auto dst = window.position(); | ||||||
|             dst.move_by(dirty_rect_in_window_coordinates.location()); |             dst.move_by(dirty_rect_in_window_coordinates.location()); | ||||||
|             if (window.opacity() == 1.0f) |             if (window.opacity() == 1.0f) | ||||||
|                 m_back_painter->blit(dst, *backing, dirty_rect_in_window_coordinates); |                 m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates); | ||||||
|             else |             else | ||||||
|                 m_back_painter->blit_with_opacity(dst, *backing, dirty_rect_in_window_coordinates, window.opacity()); |                 m_back_painter->blit_with_opacity(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity()); | ||||||
|             m_back_painter->clear_clip_rect(); |             m_back_painter->clear_clip_rect(); | ||||||
|         } |         } | ||||||
|         m_back_painter->clear_clip_rect(); |         m_back_painter->clear_clip_rect(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling