mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:42:43 +00:00 
			
		
		
		
	Let userland retain the window backing store while drawing into it.
To start painting, call: gui$get_window_backing_store() Then finish up with: gui$release_window_backing_store() Process will retain the underlying GraphicsBitmap behind the scenes. This fixes racing between the WindowServer and GUI clients. This patch also adds a WSWindowLocker that is exactly what it sounds like.
This commit is contained in:
		
							parent
							
								
									ccf3fc4618
								
							
						
					
					
						commit
						86eae0f8df
					
				
					 22 changed files with 244 additions and 102 deletions
				
			
		|  | @ -7,5 +7,5 @@ | |||
| [0m | ||||
| Welcome to Serenity OS. | ||||
| 
 | ||||
| Copyright (C) Andreas Kling, 2018 | ||||
| Copyright (C) Andreas Kling, 2018-2019 | ||||
| All rights reserved. | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ struct GUI_WindowParameters { | |||
| }; | ||||
| 
 | ||||
| struct GUI_WindowBackingStoreInfo { | ||||
|     void* backing_store_id; | ||||
|     GUI_Size size; | ||||
|     size_t bpp; | ||||
|     size_t pitch; | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ class Region; | |||
| class VMObject; | ||||
| class Zone; | ||||
| class WSWindow; | ||||
| class GraphicsBitmap; | ||||
| 
 | ||||
| #define COOL_GLOBALS | ||||
| #ifdef COOL_GLOBALS | ||||
|  | @ -197,9 +198,12 @@ public: | |||
|     int gui$create_window(const GUI_WindowParameters*); | ||||
|     int gui$destroy_window(int window_id); | ||||
|     int gui$get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo*); | ||||
|     int gui$release_window_backing_store(void* backing_store_id); | ||||
|     int gui$invalidate_window(int window_id, const GUI_Rect*); | ||||
|     int gui$get_window_parameters(int window_id, GUI_WindowParameters*); | ||||
|     int gui$set_window_parameters(int window_id, const GUI_WindowParameters*); | ||||
|     int gui$get_window_title(int window_id, char* buffer, size_t size); | ||||
|     int gui$set_window_title(int window_id, const char* title, size_t size); | ||||
|     int gui$get_window_rect(int window_id, GUI_Rect*); | ||||
|     int gui$set_window_rect(int window_id, const GUI_Rect*); | ||||
| 
 | ||||
|     DisplayInfo get_display_info(); | ||||
| 
 | ||||
|  | @ -360,6 +364,7 @@ private: | |||
|     RetainPtr<Region> m_display_framebuffer_region; | ||||
| 
 | ||||
|     HashMap<int, OwnPtr<WSWindow>> m_windows; | ||||
|     Vector<RetainPtr<GraphicsBitmap>> m_retained_backing_stores; | ||||
| 
 | ||||
|     Vector<GUI_Event> m_gui_events; | ||||
|     Lock m_gui_events_lock; | ||||
|  |  | |||
|  | @ -97,13 +97,28 @@ int Process::gui$get_window_backing_store(int window_id, GUI_WindowBackingStoreI | |||
|     if (it == m_windows.end()) | ||||
|         return -EBADWINDOW; | ||||
|     auto& window = *(*it).value; | ||||
|     WSWindowLocker locker(window); | ||||
|     auto* backing_store = window.backing(); | ||||
|     m_retained_backing_stores.append(backing_store); | ||||
|     info->backing_store_id = backing_store; | ||||
|     info->bpp = sizeof(RGBA32); | ||||
|     info->pitch = window.backing()->pitch(); | ||||
|     info->size = window.backing()->size(); | ||||
|     info->pixels = reinterpret_cast<RGBA32*>(window.backing()->client_region()->laddr().as_ptr()); | ||||
|     info->pitch = backing_store->pitch(); | ||||
|     info->size = backing_store->size(); | ||||
|     info->pixels = reinterpret_cast<RGBA32*>(backing_store->client_region()->laddr().as_ptr()); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int Process::gui$release_window_backing_store(void* backing_store_id) | ||||
| { | ||||
|     for (size_t i = 0; i < m_retained_backing_stores.size(); ++i) { | ||||
|         if (m_retained_backing_stores[i].ptr() == backing_store_id) { | ||||
|             m_retained_backing_stores.remove(i); | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|     return -EBADBACKING; | ||||
| } | ||||
| 
 | ||||
| int Process::gui$invalidate_window(int window_id, const GUI_Rect* rect) | ||||
| { | ||||
|     if (window_id < 0) | ||||
|  | @ -121,39 +136,82 @@ int Process::gui$invalidate_window(int window_id, const GUI_Rect* rect) | |||
| #endif | ||||
|     auto& window = *(*it).value; | ||||
|     Rect invalidation_rect; | ||||
|     if (rect) | ||||
|     if (rect) { | ||||
|         WSWindowLocker locker(window); | ||||
|         invalidation_rect = *rect; | ||||
|     } | ||||
|     WSEventLoop::the().post_event(&window, make<WSWindowInvalidationEvent>(invalidation_rect)); | ||||
|     WSEventLoop::the().server_process().request_wakeup(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int Process::gui$get_window_parameters(int window_id, GUI_WindowParameters* params) | ||||
| int Process::gui$get_window_title(int window_id, char* buffer, size_t size) | ||||
| { | ||||
|     if (window_id < 0) | ||||
|         return -EINVAL; | ||||
|     if (!validate_write_typed(params)) | ||||
|     if (!validate_write(buffer, size)) | ||||
|         return -EFAULT; | ||||
|     auto it = m_windows.find(window_id); | ||||
|     if (it == m_windows.end()) | ||||
|         return -EBADWINDOW; | ||||
|     auto& window = *(*it).value; | ||||
|     params->rect = window.rect(); | ||||
|     strcpy(params->title, window.title().characters()); | ||||
|     String title; | ||||
|     { | ||||
|         WSWindowLocker locker(window); | ||||
|         title = window.title(); | ||||
|     } | ||||
|     if (title.length() > size) | ||||
|         return -ERANGE; | ||||
|     memcpy(buffer, title.characters(), title.length()); | ||||
|     return title.length(); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| int Process::gui$set_window_title(int window_id, const char* title, size_t size) | ||||
| { | ||||
|     if (window_id < 0) | ||||
|         return -EINVAL; | ||||
|     if (!validate_read(title, size)) | ||||
|         return -EFAULT; | ||||
|     auto it = m_windows.find(window_id); | ||||
|     if (it == m_windows.end()) | ||||
|         return -EBADWINDOW; | ||||
|     auto& window = *(*it).value; | ||||
|     String new_title(title, size); | ||||
|     WSEventLoop::the().post_event(&window, make<WSSetWindowTitle>(move(new_title))); | ||||
|     WSEventLoop::the().server_process().request_wakeup(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int Process::gui$set_window_parameters(int window_id, const GUI_WindowParameters* params) | ||||
| int Process::gui$get_window_rect(int window_id, GUI_Rect* rect) | ||||
| { | ||||
|     if (window_id < 0) | ||||
|         return -EINVAL; | ||||
|     if (!validate_read_typed(params)) | ||||
|     if (!validate_write_typed(rect)) | ||||
|         return -EFAULT; | ||||
|     auto it = m_windows.find(window_id); | ||||
|     if (it == m_windows.end()) | ||||
|         return -EBADWINDOW; | ||||
|     auto& window = *(*it).value; | ||||
|     window.set_rect(params->rect); | ||||
|     window.set_title(params->title); | ||||
|     { | ||||
|         WSWindowLocker locker(window); | ||||
|         *rect = window.rect(); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| int Process::gui$set_window_rect(int window_id, const GUI_Rect* rect) | ||||
| { | ||||
|     if (window_id < 0) | ||||
|         return -EINVAL; | ||||
|     if (!validate_read_typed(rect)) | ||||
|         return -EFAULT; | ||||
|     auto it = m_windows.find(window_id); | ||||
|     if (it == m_windows.end()) | ||||
|         return -EBADWINDOW; | ||||
|     auto& window = *(*it).value; | ||||
|     Rect new_rect = *rect; | ||||
|     WSEventLoop::the().post_event(&window, make<WSSetWindowRect>(new_rect)); | ||||
|     WSEventLoop::the().server_process().request_wakeup(); | ||||
|     return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -201,12 +201,18 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2, | |||
|         return current->gui$destroy_window((int)arg1); | ||||
|     case Syscall::SC_gui_get_window_backing_store: | ||||
|         return current->gui$get_window_backing_store((int)arg1, (GUI_WindowBackingStoreInfo*)arg2); | ||||
|     case Syscall::SC_gui_release_window_backing_store: | ||||
|         return current->gui$release_window_backing_store((void*)arg1); | ||||
|     case Syscall::SC_gui_invalidate_window: | ||||
|         return current->gui$invalidate_window((int)arg1, (const GUI_Rect*)arg2); | ||||
|     case Syscall::SC_gui_set_window_parameters: | ||||
|         return current->gui$set_window_parameters((int)arg1, (const GUI_WindowParameters*)arg2); | ||||
|     case Syscall::SC_gui_get_window_parameters: | ||||
|         return current->gui$get_window_parameters((int)arg1, (GUI_WindowParameters*)arg2); | ||||
|     case Syscall::SC_gui_set_window_title: | ||||
|         return current->gui$set_window_title((int)arg1, (const char*)arg2, (size_t)arg3); | ||||
|     case Syscall::SC_gui_get_window_title: | ||||
|         return current->gui$get_window_title((int)arg1, (char*)arg2, (size_t)arg3); | ||||
|     case Syscall::SC_gui_set_window_rect: | ||||
|         return current->gui$set_window_rect((int)arg1, (const GUI_Rect*)arg2); | ||||
|     case Syscall::SC_gui_get_window_rect: | ||||
|         return current->gui$get_window_rect((int)arg1, (GUI_Rect*)arg2); | ||||
|     default: | ||||
|         kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3); | ||||
|         break; | ||||
|  |  | |||
|  | @ -67,15 +67,18 @@ | |||
|     __ENUMERATE_SYSCALL(utime) \ | ||||
|     __ENUMERATE_SYSCALL(sync) \ | ||||
|     __ENUMERATE_SYSCALL(ptsname_r) \ | ||||
|     __ENUMERATE_SYSCALL(select) \ | ||||
|     __ENUMERATE_SYSCALL(unlink) \ | ||||
|     __ENUMERATE_SYSCALL(poll) \ | ||||
|     __ENUMERATE_SYSCALL(gui_create_window) \ | ||||
|     __ENUMERATE_SYSCALL(gui_destroy_window) \ | ||||
|     __ENUMERATE_SYSCALL(gui_get_window_backing_store) \ | ||||
|     __ENUMERATE_SYSCALL(gui_release_window_backing_store) \ | ||||
|     __ENUMERATE_SYSCALL(gui_invalidate_window) \ | ||||
|     __ENUMERATE_SYSCALL(select) \ | ||||
|     __ENUMERATE_SYSCALL(gui_get_window_parameters) \ | ||||
|     __ENUMERATE_SYSCALL(gui_set_window_parameters) \ | ||||
|     __ENUMERATE_SYSCALL(unlink) \ | ||||
|     __ENUMERATE_SYSCALL(poll) \ | ||||
|     __ENUMERATE_SYSCALL(gui_get_window_title) \ | ||||
|     __ENUMERATE_SYSCALL(gui_set_window_title) \ | ||||
|     __ENUMERATE_SYSCALL(gui_get_window_rect) \ | ||||
|     __ENUMERATE_SYSCALL(gui_set_window_rect) \ | ||||
| 
 | ||||
| 
 | ||||
| struct fd_set; | ||||
|  |  | |||
|  | @ -42,7 +42,9 @@ | |||
|     __ERROR(ENOTIMPL,       "Not implemented") \ | ||||
|     __ERROR(EAFNOSUPPORT,   "Address family not supported") \ | ||||
|     __ERROR(EWHYTHO,        "Failed without setting an error code (Bug!)") \ | ||||
|     __ERROR(EBADWINDOW,     "Bad Window ID") \ | ||||
|     __ERROR(EBADWINDOW,     "Bad window ID") \ | ||||
|     __ERROR(EBADBACKING,    "Bad backing store ID") \ | ||||
| 
 | ||||
| 
 | ||||
| enum __errno_values { | ||||
| #undef __ERROR | ||||
|  |  | |||
							
								
								
									
										26
									
								
								LibC/gui.cpp
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								LibC/gui.cpp
									
										
									
									
									
								
							|  | @ -21,14 +21,32 @@ int gui_get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo* info | |||
|     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||
| } | ||||
| 
 | ||||
| int gui_get_window_parameters(int window_id, GUI_WindowParameters* params) | ||||
| int gui_release_window_backing_store(void* backing_store_id) | ||||
| { | ||||
|     int rc = syscall(SC_gui_get_window_parameters, window_id, params); | ||||
|     int rc = syscall(SC_gui_release_window_backing_store, backing_store_id); | ||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||
| } | ||||
| 
 | ||||
| int gui_set_window_parameters(int window_id, const GUI_WindowParameters* params) | ||||
| int gui_get_window_title(int window_id, char* buffer, size_t size) | ||||
| { | ||||
|     int rc = syscall(SC_gui_set_window_parameters, window_id, params); | ||||
|     int rc = syscall(SC_gui_get_window_title, window_id, buffer, size); | ||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||
| } | ||||
| 
 | ||||
| int gui_set_window_title(int window_id, const char* title, size_t length) | ||||
| { | ||||
|     int rc = syscall(SC_gui_set_window_title, window_id, title, length); | ||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||
| } | ||||
| 
 | ||||
| int gui_get_window_rect(int window_id, GUI_Rect* rect) | ||||
| { | ||||
|     int rc = syscall(SC_gui_get_window_rect, window_id, rect); | ||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||
| } | ||||
| 
 | ||||
| int gui_set_window_rect(int window_id, const GUI_Rect* rect) | ||||
| { | ||||
|     int rc = syscall(SC_gui_set_window_rect, window_id, rect); | ||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||
| } | ||||
|  |  | |||
|  | @ -8,8 +8,11 @@ __BEGIN_DECLS | |||
| int gui_create_window(const GUI_WindowParameters*); | ||||
| int gui_invalidate_window(int window_id, const GUI_Rect*); | ||||
| int gui_get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo*); | ||||
| int gui_get_window_parameters(int window_id, GUI_WindowParameters*); | ||||
| int gui_set_window_parameters(int window_id, const GUI_WindowParameters*); | ||||
| int gui_release_window_backing_store(void* backing_store_id); | ||||
| int gui_get_window_title(int window_id, char*, size_t); | ||||
| int gui_set_window_title(int window_id, const char*, size_t); | ||||
| int gui_get_window_rect(int window_id, GUI_Rect*); | ||||
| int gui_set_window_rect(int window_id, const GUI_Rect*); | ||||
| 
 | ||||
| __END_DECLS | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,12 +18,13 @@ GWidget::~GWidget() | |||
| { | ||||
| } | ||||
| 
 | ||||
| void GWidget::set_relative_rect(const Rect& rect, bool should_update) | ||||
| void GWidget::set_relative_rect(const Rect& rect) | ||||
| { | ||||
|     if (rect == m_relative_rect) | ||||
|         return; | ||||
|     // FIXME: Make some kind of event loop driven ResizeEvent?
 | ||||
|     m_relative_rect = rect; | ||||
|     if (should_update) | ||||
|         update(); | ||||
|     update(); | ||||
| } | ||||
| 
 | ||||
| void GWidget::repaint(const Rect& rect) | ||||
|  | @ -147,10 +148,3 @@ void GWidget::set_font(RetainPtr<Font>&& font) | |||
|     else | ||||
|         m_font = move(font); | ||||
| } | ||||
| 
 | ||||
| GraphicsBitmap* GWidget::backing() | ||||
| { | ||||
|     if (auto* w = window()) | ||||
|         return w->backing(); | ||||
|     return nullptr; | ||||
| } | ||||
|  |  | |||
|  | @ -51,7 +51,7 @@ public: | |||
| 
 | ||||
|     virtual const char* class_name() const override { return "GWidget"; } | ||||
| 
 | ||||
|     void set_relative_rect(const Rect&, bool should_update = true); | ||||
|     void set_relative_rect(const Rect&); | ||||
| 
 | ||||
|     Color background_color() const { return m_background_color; } | ||||
|     Color foreground_color() const { return m_foreground_color; } | ||||
|  | @ -84,8 +84,6 @@ public: | |||
|     const Font& font() const { return *m_font; } | ||||
|     void set_font(RetainPtr<Font>&&); | ||||
| 
 | ||||
|     GraphicsBitmap* backing(); | ||||
| 
 | ||||
| private: | ||||
|     GWindow* m_window { nullptr }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,14 +39,6 @@ GWindow::GWindow(GObject* parent) | |||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     GUI_WindowBackingStoreInfo backing; | ||||
|     int rc = gui_get_window_backing_store(m_window_id, &backing); | ||||
|     if (rc < 0) { | ||||
|         perror("gui_get_window_backing_store"); | ||||
|         exit(1); | ||||
|     } | ||||
|     m_backing = GraphicsBitmap::create_wrapper(backing.size, backing.pixels); | ||||
| 
 | ||||
|     windows().set(m_window_id, this); | ||||
| } | ||||
| 
 | ||||
|  | @ -58,34 +50,16 @@ void GWindow::set_title(String&& title) | |||
| { | ||||
|     dbgprintf("GWindow::set_title \"%s\"\n", title.characters()); | ||||
|     GUI_WindowParameters params; | ||||
|     int rc = gui_get_window_parameters(m_window_id, ¶ms); | ||||
|     int rc = gui_set_window_title(m_window_id, title.characters(), title.length()); | ||||
|     ASSERT(rc == 0); | ||||
|     strcpy(params.title, title.characters());; | ||||
|     rc = gui_set_window_parameters(m_window_id, ¶ms); | ||||
|     ASSERT(rc == 0); | ||||
|     m_title = move(title); | ||||
| } | ||||
| 
 | ||||
| void GWindow::set_rect(const Rect& rect) | ||||
| void GWindow::set_rect(const Rect& a_rect) | ||||
| { | ||||
|     // FIXME: This is a hack to fudge the race with WSWindowManager trying to display @ old rect.
 | ||||
|     sleep(10); | ||||
| 
 | ||||
|     dbgprintf("GWindow::set_rect %d,%d %dx%d\n", m_rect.x(), m_rect.y(), m_rect.width(), m_rect.height()); | ||||
|     GUI_WindowParameters params; | ||||
|     int rc = gui_get_window_parameters(m_window_id, ¶ms); | ||||
|     dbgprintf("GWindow::set_rect! %d,%d %dx%d\n", a_rect.x(), a_rect.y(), a_rect.width(), a_rect.height()); | ||||
|     GUI_Rect rect = a_rect; | ||||
|     int rc = gui_set_window_rect(m_window_id, &rect); | ||||
|     ASSERT(rc == 0); | ||||
|     params.rect = rect; | ||||
|     rc = gui_set_window_parameters(m_window_id, ¶ms); | ||||
|     ASSERT(rc == 0); | ||||
|     m_rect = rect; | ||||
|     GUI_WindowBackingStoreInfo backing; | ||||
|     rc = gui_get_window_backing_store(m_window_id, &backing); | ||||
|     if (rc < 0) { | ||||
|         perror("gui_get_window_backing_store"); | ||||
|         exit(1); | ||||
|     } | ||||
|     m_backing = GraphicsBitmap::create_wrapper(backing.size, backing.pixels); | ||||
| } | ||||
| 
 | ||||
| void GWindow::event(GEvent& event) | ||||
|  |  | |||
|  | @ -16,20 +16,17 @@ public: | |||
| 
 | ||||
|     int window_id() const { return m_window_id; } | ||||
| 
 | ||||
|     String title() const { return m_title; } | ||||
|     void set_title(String&&); | ||||
| 
 | ||||
|     int x() const { return m_rect.x(); } | ||||
|     int y() const { return m_rect.y(); } | ||||
|     int width() const { return m_rect.width(); } | ||||
|     int height() const { return m_rect.height(); } | ||||
|     int x() const { return rect().x(); } | ||||
|     int y() const { return rect().y(); } | ||||
|     int width() const { return rect().width(); } | ||||
|     int height() const { return rect().height(); } | ||||
| 
 | ||||
|     const Rect& rect() const { return m_rect; } | ||||
|     Rect rect() const; | ||||
|     void set_rect(const Rect&); | ||||
|     void set_rect_without_repaint(const Rect& rect) { m_rect = rect; } | ||||
| 
 | ||||
|     Point position() const { return m_rect.location(); } | ||||
|     void set_position_without_repaint(const Point& position) { set_rect_without_repaint({ position.x(), position.y(), width(), height() }); } | ||||
|     Point position() const { return rect().location(); } | ||||
| 
 | ||||
|     virtual void event(GEvent&) override; | ||||
| 
 | ||||
|  | @ -41,16 +38,11 @@ public: | |||
|     const GWidget* main_widget() const { return m_main_widget; } | ||||
|     void set_main_widget(GWidget*); | ||||
| 
 | ||||
|     GraphicsBitmap* backing() { return m_backing.ptr(); } | ||||
| 
 | ||||
|     void show(); | ||||
| 
 | ||||
|     void update(); | ||||
| 
 | ||||
| private: | ||||
|     String m_title; | ||||
|     Rect m_rect; | ||||
| 
 | ||||
|     RetainPtr<GraphicsBitmap> m_backing; | ||||
|     int m_window_id { -1 }; | ||||
|     GWidget* m_main_widget { nullptr }; | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "Color.h" | ||||
| #include "Rect.h" | ||||
| #include "Size.h" | ||||
| #include <AK/Retainable.h> | ||||
| #include <AK/RetainPtr.h> | ||||
|  | @ -20,6 +21,7 @@ public: | |||
|     RGBA32* scanline(int y); | ||||
|     const RGBA32* scanline(int y) const; | ||||
| 
 | ||||
|     Rect rect() const { return { {}, m_size }; } | ||||
|     Size size() const { return m_size; } | ||||
|     int width() const { return m_size.width(); } | ||||
|     int height() const { return m_size.height(); } | ||||
|  |  | |||
|  | @ -7,6 +7,8 @@ | |||
| #ifdef LIBGUI | ||||
| #include <LibGUI/GWidget.h> | ||||
| #include <LibGUI/GWindow.h> | ||||
| #include <LibC/gui.h> | ||||
| #include <LibC/stdio.h> | ||||
| #endif | ||||
| 
 | ||||
| #define DEBUG_WIDGET_UNDERDRAW | ||||
|  | @ -22,12 +24,20 @@ Painter::Painter(GraphicsBitmap& bitmap) | |||
| Painter::Painter(GWidget& widget) | ||||
|     : m_font(&widget.font()) | ||||
| { | ||||
|     m_target = widget.backing(); | ||||
|     GUI_WindowBackingStoreInfo backing; | ||||
|     int rc = gui_get_window_backing_store(widget.window()->window_id(), &backing); | ||||
|     if (rc < 0) { | ||||
|         perror("gui_get_window_backing_store"); | ||||
|         exit(1); | ||||
|     } | ||||
|     m_backing_store_id = backing.backing_store_id; | ||||
|     m_target = GraphicsBitmap::create_wrapper(backing.size, backing.pixels); | ||||
|     ASSERT(m_target); | ||||
|     m_window = widget.window(); | ||||
|     m_translation.move_by(widget.relative_position()); | ||||
|     // NOTE: m_clip_rect is in Window coordinates since we are painting into its backing store.
 | ||||
|     m_clip_rect = widget.relative_rect(); | ||||
|     m_clip_rect.intersect(m_target->rect()); | ||||
| 
 | ||||
| #ifdef DEBUG_WIDGET_UNDERDRAW | ||||
|     // If the widget is not opaque, let's not mess it up with debugging color.
 | ||||
|  | @ -39,6 +49,11 @@ Painter::Painter(GWidget& widget) | |||
| 
 | ||||
| Painter::~Painter() | ||||
| { | ||||
| #ifdef LIBGUI | ||||
|     m_target = nullptr; | ||||
|     int rc = gui_release_window_backing_store(m_backing_store_id); | ||||
|     ASSERT(rc == 0); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void Painter::fill_rect(const Rect& a_rect, Color color) | ||||
|  | @ -47,6 +62,9 @@ void Painter::fill_rect(const Rect& a_rect, Color color) | |||
|     rect.move_by(m_translation); | ||||
|     rect.intersect(m_clip_rect); | ||||
| 
 | ||||
|     if (rect.is_empty()) | ||||
|         return; | ||||
| 
 | ||||
|     RGBA32* dst = m_target->scanline(rect.top()) + rect.left(); | ||||
|     const unsigned dst_skip = m_target->width(); | ||||
| 
 | ||||
|  | @ -266,3 +284,13 @@ void Painter::blit(const Point& position, const GraphicsBitmap& source, const Re | |||
|         src += src_skip; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Painter::set_clip_rect(const Rect& rect) | ||||
| { | ||||
|     m_clip_rect = Rect::intersection(rect, m_target->rect()); | ||||
| } | ||||
| 
 | ||||
| void Painter::clear_clip_rect() | ||||
| { | ||||
|     m_clip_rect = m_target->rect(); | ||||
| } | ||||
|  |  | |||
|  | @ -40,8 +40,8 @@ public: | |||
|     void set_draw_op(DrawOp op) { m_draw_op = op; } | ||||
|     DrawOp draw_op() const { return m_draw_op; } | ||||
| 
 | ||||
|     void set_clip_rect(const Rect& rect) { m_clip_rect = rect; } | ||||
|     void clear_clip_rect() { m_clip_rect = { 0, 0, 1024, 768 }; } | ||||
|     void set_clip_rect(const Rect& rect); | ||||
|     void clear_clip_rect(); | ||||
|     Rect clip_rect() const { return m_clip_rect; } | ||||
| 
 | ||||
| private: | ||||
|  | @ -53,6 +53,7 @@ private: | |||
|     RetainPtr<GraphicsBitmap> m_target; | ||||
| #ifdef LIBGUI | ||||
|     GWindow* m_window { nullptr }; | ||||
|     void* m_backing_store_id { nullptr }; | ||||
| #endif | ||||
|     DrawOp m_draw_op { DrawOp::Copy }; | ||||
| }; | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ void Terminal::create_window() | |||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     // NOTE: We never release the backing store.
 | ||||
|     GUI_WindowBackingStoreInfo info; | ||||
|     int rc = gui_get_window_backing_store(m_window_id, &info); | ||||
|     if (rc < 0) { | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ int main(int argc, char** argv) | |||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     // NOTE: We never release the backing store. This is just a simple app. :^)
 | ||||
|     GUI_WindowBackingStoreInfo backing; | ||||
|     int rc = gui_get_window_backing_store(window_id, &backing); | ||||
|     if (rc < 0) { | ||||
|  |  | |||
|  | @ -39,6 +39,8 @@ public: | |||
|         WM_Invalidate, | ||||
|         WindowActivated, | ||||
|         WindowDeactivated, | ||||
|         WM_SetWindowTitle, | ||||
|         WM_SetWindowRect, | ||||
|     }; | ||||
| 
 | ||||
|     WSEvent() { } | ||||
|  | @ -70,6 +72,34 @@ private: | |||
|     Rect m_rect; | ||||
| }; | ||||
| 
 | ||||
| class WSSetWindowTitle final : public WSEvent { | ||||
| public: | ||||
|     explicit WSSetWindowTitle(String&& title) | ||||
|         : WSEvent(WSEvent::WM_SetWindowTitle) | ||||
|         , m_title(move(title)) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     String title() const { return m_title; } | ||||
| 
 | ||||
| private: | ||||
|     String m_title; | ||||
| }; | ||||
| 
 | ||||
| class WSSetWindowRect final : public WSEvent { | ||||
| public: | ||||
|     explicit WSSetWindowRect(const Rect& rect) | ||||
|         : WSEvent(WSEvent::WM_SetWindowRect) | ||||
|         , m_rect(rect) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     Rect rect() const { return m_rect; } | ||||
| 
 | ||||
| private: | ||||
|     Rect m_rect; | ||||
| }; | ||||
| 
 | ||||
| class WSPaintEvent final : public WSEvent { | ||||
| public: | ||||
|     explicit WSPaintEvent(const Rect& rect = Rect()) | ||||
|  |  | |||
|  | @ -19,21 +19,28 @@ WSWindow::~WSWindow() | |||
| 
 | ||||
| void WSWindow::set_title(String&& title) | ||||
| { | ||||
|     if (m_title == title) | ||||
|         return; | ||||
|     { | ||||
|         WSWindowLocker locker(*this); | ||||
|         if (m_title == title) | ||||
|             return; | ||||
|         m_title = move(title); | ||||
|     } | ||||
| 
 | ||||
|     m_title = move(title); | ||||
|     WSWindowManager::the().notify_title_changed(*this); | ||||
| } | ||||
| 
 | ||||
| void WSWindow::set_rect(const Rect& rect) | ||||
| { | ||||
|     if (m_rect == rect) | ||||
|         return; | ||||
|     auto old_rect = m_rect; | ||||
|     m_rect = rect; | ||||
|     m_backing = GraphicsBitmap::create(m_process, m_rect.size()); | ||||
|     WSWindowManager::the().notify_rect_changed(*this, old_rect, m_rect); | ||||
|     Rect old_rect; | ||||
|     { | ||||
|         WSWindowLocker locker(*this); | ||||
|         if (m_rect == rect) | ||||
|             return; | ||||
|         old_rect = m_rect; | ||||
|         m_rect = rect; | ||||
|         m_backing = GraphicsBitmap::create(m_process, m_rect.size()); | ||||
|     } | ||||
|     WSWindowManager::the().notify_rect_changed(*this, old_rect, rect); | ||||
| } | ||||
| 
 | ||||
| // FIXME: Just use the same types.
 | ||||
|  | @ -86,6 +93,12 @@ void WSWindow::event(WSEvent& event) | |||
|     case WSEvent::WM_Invalidate: | ||||
|         WSWindowManager::the().invalidate(*this, static_cast<WSWindowInvalidationEvent&>(event).rect()); | ||||
|         return; | ||||
|     case WSEvent::WM_SetWindowRect: | ||||
|         set_rect(static_cast<WSSetWindowRect&>(event).rect()); | ||||
|         return; | ||||
|     case WSEvent::WM_SetWindowTitle: | ||||
|         set_title(static_cast<WSSetWindowTitle&>(event).title()); | ||||
|         return; | ||||
|     case WSEvent::WindowActivated: | ||||
|         gui_event.type = GUI_Event::Type::WindowActivated; | ||||
|         break; | ||||
|  |  | |||
|  | @ -4,11 +4,13 @@ | |||
| #include <SharedGraphics/GraphicsBitmap.h> | ||||
| #include <AK/AKString.h> | ||||
| #include <AK/InlineLinkedList.h> | ||||
| #include <AK/Lock.h> | ||||
| #include "WSEventReceiver.h" | ||||
| 
 | ||||
| class Process; | ||||
| 
 | ||||
| class WSWindow final : public WSEventReceiver, public InlineLinkedListNode<WSWindow> { | ||||
|     friend class WSWindowLocker; | ||||
| public: | ||||
|     WSWindow(Process&, int window_id); | ||||
|     virtual ~WSWindow() override; | ||||
|  | @ -46,6 +48,7 @@ public: | |||
|     WSWindow* m_prev { nullptr }; | ||||
| 
 | ||||
| private: | ||||
|     Lock m_lock; | ||||
|     String m_title; | ||||
|     Rect m_rect; | ||||
|     bool m_is_being_dragged { false }; | ||||
|  | @ -56,3 +59,11 @@ private: | |||
|     pid_t m_pid { -1 }; | ||||
| }; | ||||
| 
 | ||||
| class WSWindowLocker { | ||||
| public: | ||||
|     WSWindowLocker(WSWindow& window) : m_locker(window.m_lock) { } | ||||
|     ~WSWindowLocker() { } | ||||
| private: | ||||
|     Locker m_locker; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -220,13 +220,13 @@ void WSWindowManager::remove_window(WSWindow& window) | |||
| void WSWindowManager::notify_title_changed(WSWindow& window) | ||||
| { | ||||
|     printf("[WM] WSWindow{%p} title set to '%s'\n", &window, window.title().characters()); | ||||
|     invalidate(outer_window_rect(window.rect())); | ||||
| } | ||||
| 
 | ||||
| void WSWindowManager::notify_rect_changed(WSWindow& window, const Rect& old_rect, const Rect& new_rect) | ||||
| { | ||||
|     printf("[WM] WSWindow %p rect changed (%d,%d %dx%d) -> (%d,%d %dx%d)\n", &window, old_rect.x(), old_rect.y(), old_rect.width(), old_rect.height(), new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height()); | ||||
|     ASSERT_INTERRUPTS_ENABLED(); | ||||
|     LOCKER(m_lock); | ||||
|     invalidate(outer_window_rect(old_rect)); | ||||
|     invalidate(outer_window_rect(new_rect)); | ||||
| } | ||||
|  | @ -335,6 +335,7 @@ void WSWindowManager::compose() | |||
|         m_back_painter->fill_rect(dirty_rect, Color(0, 72, 96)); | ||||
|     } | ||||
|     for (auto* window = m_windows_in_order.head(); window; window = window->next()) { | ||||
|         WSWindowLocker locker(*window); | ||||
|         if (!window->backing()) | ||||
|             continue; | ||||
|         if (!any_dirty_rect_intersects_window(*window)) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling