diff options
-rw-r--r-- | Kernel/Process.h | 1 | ||||
-rw-r--r-- | Kernel/ProcessGUI.cpp | 42 | ||||
-rw-r--r-- | Kernel/Syscall.cpp | 2 | ||||
-rw-r--r-- | Kernel/Syscall.h | 1 | ||||
-rw-r--r-- | LibC/gui.cpp | 6 | ||||
-rw-r--r-- | LibC/gui.h | 1 | ||||
-rw-r--r-- | LibGUI/GEventLoop.cpp | 2 | ||||
-rw-r--r-- | LibGUI/GWidget.cpp | 2 | ||||
-rw-r--r-- | LibGUI/GWindow.cpp | 17 | ||||
-rw-r--r-- | LibGUI/GWindow.h | 3 | ||||
-rw-r--r-- | SharedGraphics/GraphicsBitmap.cpp | 10 | ||||
-rw-r--r-- | Terminal/Terminal.cpp | 39 | ||||
-rw-r--r-- | Terminal/Terminal.h | 4 | ||||
-rw-r--r-- | Terminal/main.cpp | 4 | ||||
-rw-r--r-- | Userland/guitest.cpp | 8 | ||||
-rw-r--r-- | WindowServer/WSEventLoop.cpp | 15 |
16 files changed, 117 insertions, 40 deletions
diff --git a/Kernel/Process.h b/Kernel/Process.h index 1949ba08d0..2d42952bcc 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -201,6 +201,7 @@ public: 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$notify_paint_finished(int window_id, const GUI_Rect*); 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*); diff --git a/Kernel/ProcessGUI.cpp b/Kernel/ProcessGUI.cpp index 01477a12b4..45214106d6 100644 --- a/Kernel/ProcessGUI.cpp +++ b/Kernel/ProcessGUI.cpp @@ -126,28 +126,50 @@ int Process::gui$release_window_backing_store(void* backing_store_id) return -EBADBACKING; } -int Process::gui$invalidate_window(int window_id, const GUI_Rect* rect) +int Process::gui$invalidate_window(int window_id, const GUI_Rect* a_rect) { if (window_id < 0) return -EINVAL; - if (rect && !validate_read_typed(rect)) + if (a_rect && !validate_read_typed(a_rect)) return -EFAULT; auto it = m_windows.find(window_id); if (it == m_windows.end()) return -EBADWINDOW; #ifdef LOG_GUI_SYSCALLS - if (!rect) + if (!a_rect) dbgprintf("%s<%u> gui$invalidate_window (window_id=%d, rect=(entire))\n", name().characters(), pid(), window_id); else - dbgprintf("%s<%u> gui$invalidate_window (window_id=%d, rect={%d,%d %dx%d})\n", name().characters(), pid(), window_id, rect->location.x, rect->location.y, rect->size.width, rect->size.height); + dbgprintf("%s<%u> gui$invalidate_window (window_id=%d, rect={%d,%d %dx%d})\n", name().characters(), pid(), window_id, a_rect->location.x, a_rect->location.y, a_rect->size.width, a_rect->size.height); #endif auto& window = *(*it).value; - Rect invalidation_rect; - if (rect) { - WSWindowLocker locker(window); - invalidation_rect = *rect; - } - WSEventLoop::the().post_event(&window, make<WSWindowInvalidationEvent>(invalidation_rect)); + Rect rect; + if (a_rect) + rect = *a_rect; + WSEventLoop::the().post_event(&window, make<WSPaintEvent>(rect)); + WSEventLoop::the().server_process().request_wakeup(); + return 0; +} + +int Process::gui$notify_paint_finished(int window_id, const GUI_Rect* a_rect) +{ + if (window_id < 0) + return -EINVAL; + if (a_rect && !validate_read_typed(a_rect)) + return -EFAULT; + auto it = m_windows.find(window_id); + if (it == m_windows.end()) + return -EBADWINDOW; +#ifdef LOG_GUI_SYSCALLS + if (!a_rect) + dbgprintf("%s<%u> gui$notify_paint_finished (window_id=%d, rect=(entire))\n", name().characters(), pid(), window_id); + else + dbgprintf("%s<%u> gui$notify_paint_finished (window_id=%d, rect={%d,%d %dx%d})\n", name().characters(), pid(), window_id, a_rect->location.x, a_rect->location.y, a_rect->size.width, a_rect->size.height); +#endif + auto& window = *(*it).value; + Rect rect; + if (a_rect) + rect = *a_rect; + WSEventLoop::the().post_event(&window, make<WSWindowInvalidationEvent>(rect)); WSEventLoop::the().server_process().request_wakeup(); return 0; } diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 122a559b20..abb350603c 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -215,6 +215,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2, return current->gui$get_window_rect((int)arg1, (GUI_Rect*)arg2); case Syscall::SC_read_tsc: return current->sys$read_tsc((dword*)arg1, (dword*)arg2); + case Syscall::SC_gui_notify_paint_finished: + return current->gui$notify_paint_finished((int)arg1, (const GUI_Rect*)arg2); default: kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3); break; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 7acd4e0a9f..08c051a1b6 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -80,6 +80,7 @@ __ENUMERATE_SYSCALL(gui_set_window_title) \ __ENUMERATE_SYSCALL(gui_get_window_rect) \ __ENUMERATE_SYSCALL(gui_set_window_rect) \ + __ENUMERATE_SYSCALL(gui_notify_paint_finished) \ #ifdef SERENITY diff --git a/LibC/gui.cpp b/LibC/gui.cpp index 37bd1e8907..641ec3ffdc 100644 --- a/LibC/gui.cpp +++ b/LibC/gui.cpp @@ -50,3 +50,9 @@ 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); } + +int gui_notify_paint_finished(int window_id, const GUI_Rect* rect) +{ + int rc = syscall(SC_gui_notify_paint_finished, window_id, rect); + __RETURN_WITH_ERRNO(rc, rc, -1); +} diff --git a/LibC/gui.h b/LibC/gui.h index c4900dc363..de4e62f7c9 100644 --- a/LibC/gui.h +++ b/LibC/gui.h @@ -7,6 +7,7 @@ __BEGIN_DECLS int gui_create_window(const GUI_WindowParameters*); int gui_invalidate_window(int window_id, const GUI_Rect*); +int gui_notify_paint_finished(int window_id, const GUI_Rect*); int gui_get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo*); int gui_release_window_backing_store(void* backing_store_id); int gui_get_window_title(int window_id, char*, size_t); diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index 45bfee7822..78858d7cde 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -134,7 +134,7 @@ void GEventLoop::wait_for_event() } switch (event.type) { case GUI_Event::Type::Paint: - dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break; + dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); handle_paint_event(event, *window); break; case GUI_Event::Type::MouseDown: diff --git a/LibGUI/GWidget.cpp b/LibGUI/GWidget.cpp index feb84a1f95..9ccc18279c 100644 --- a/LibGUI/GWidget.cpp +++ b/LibGUI/GWidget.cpp @@ -106,7 +106,7 @@ void GWidget::update() if (m_has_pending_paint_event) return; m_has_pending_paint_event = true; - GEventLoop::main().post_event(w, make<GPaintEvent>(relative_rect())); + w->update(relative_rect()); } GWidget::HitTestResult GWidget::hit_test(int x, int y) diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp index 8cf791a6b0..0df190493c 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -49,11 +49,18 @@ GWindow::~GWindow() void GWindow::set_title(String&& title) { dbgprintf("GWindow::set_title \"%s\"\n", title.characters()); - GUI_WindowParameters params; int rc = gui_set_window_title(m_window_id, title.characters(), title.length()); ASSERT(rc == 0); } +String GWindow::title() const +{ + char buffer[256]; + int rc = gui_get_window_title(m_window_id, buffer, sizeof(buffer)); + ASSERT(rc >= 0); + return String(buffer, rc); +} + void GWindow::set_rect(const Rect& a_rect) { dbgprintf("GWindow::set_rect! %d,%d %dx%d\n", a_rect.x(), a_rect.y(), a_rect.width(), a_rect.height()); @@ -85,7 +92,7 @@ void GWindow::event(GEvent& event) rect = m_main_widget->rect(); m_main_widget->event(*make<GPaintEvent>(rect)); GUI_Rect gui_rect = rect; - int rc = gui_invalidate_window(m_window_id, &gui_rect); + int rc = gui_notify_paint_finished(m_window_id, &gui_rect); ASSERT(rc == 0); } @@ -105,9 +112,11 @@ void GWindow::show() { } -void GWindow::update() +void GWindow::update(const Rect& a_rect) { - GEventLoop::main().post_event(this, make<GPaintEvent>()); + GUI_Rect rect = a_rect; + int rc = gui_invalidate_window(m_window_id, a_rect.is_null() ? nullptr : &rect); + ASSERT(rc == 0); } void GWindow::set_main_widget(GWidget* widget) diff --git a/LibGUI/GWindow.h b/LibGUI/GWindow.h index 8d45067672..7f2bbd708f 100644 --- a/LibGUI/GWindow.h +++ b/LibGUI/GWindow.h @@ -16,6 +16,7 @@ public: int window_id() const { return m_window_id; } + String title() const; void set_title(String&&); int x() const { return rect().x(); } @@ -40,7 +41,7 @@ public: void show(); - void update(); + void update(const Rect& = Rect()); private: RetainPtr<GraphicsBitmap> m_backing; diff --git a/SharedGraphics/GraphicsBitmap.cpp b/SharedGraphics/GraphicsBitmap.cpp index c90c3aef46..c6a1177ba8 100644 --- a/SharedGraphics/GraphicsBitmap.cpp +++ b/SharedGraphics/GraphicsBitmap.cpp @@ -18,18 +18,16 @@ GraphicsBitmap::GraphicsBitmap(Process& process, const Size& size) , m_pitch(size.width() * sizeof(RGBA32)) , m_client_process(&process) { + InterruptDisabler disabler; size_t size_in_bytes = size.width() * size.height() * sizeof(RGBA32); auto vmo = VMObject::create_anonymous(size_in_bytes); m_client_region = process.allocate_region_with_vmo(LinearAddress(), size_in_bytes, vmo.copyRef(), 0, "GraphicsBitmap (client)", true, true); m_client_region->set_shared(true); m_client_region->commit(); + auto& server = WSEventLoop::the().server_process(); + m_server_region = server.allocate_region_with_vmo(LinearAddress(), size_in_bytes, move(vmo), 0, "GraphicsBitmap (server)", true, false); + m_server_region->set_shared(true); - { - auto& server = WSEventLoop::the().server_process(); - InterruptDisabler disabler; - m_server_region = server.allocate_region_with_vmo(LinearAddress(), size_in_bytes, move(vmo), 0, "GraphicsBitmap (server)", true, false); - m_server_region->set_shared(true); - } m_data = (RGBA32*)m_server_region->laddr().as_ptr(); } #endif diff --git a/Terminal/Terminal.cpp b/Terminal/Terminal.cpp index a4a00df443..b4decc8ef1 100644 --- a/Terminal/Terminal.cpp +++ b/Terminal/Terminal.cpp @@ -88,7 +88,7 @@ Terminal::Line::Line(word columns) { characters = new byte[length]; attributes = new Attribute[length]; - needs_invalidation = false; + did_paint = false; memset(characters, ' ', length); } @@ -603,7 +603,7 @@ void Terminal::paint() Painter painter(*m_backing); for (size_t i = 0; i < rows(); ++i) - line(i).needs_invalidation = false; + line(i).did_paint = false; if (m_rows_to_scroll_backing_store && m_rows_to_scroll_backing_store < m_rows) { int first_scanline = m_inset; @@ -630,7 +630,7 @@ void Terminal::paint() painter.fill_rect(row_rect(row), line.attributes[0].background_color); for (word column = 0; column < m_columns; ++column) { auto& attribute = line.attributes[column]; - line.needs_invalidation = true; + line.did_paint = true; char ch = line.characters[column]; auto character_rect = glyph_rect(row, column); if (!has_only_one_background_color) { @@ -649,7 +649,7 @@ void Terminal::paint() else painter.draw_rect(cursor_rect, Color::MidGray); - line(m_cursor_row).needs_invalidation = true; + line(m_cursor_row).did_paint = true; if (m_belling) { m_need_full_invalidation = true; @@ -657,23 +657,38 @@ void Terminal::paint() } if (m_need_full_invalidation) { - invalidate_window(); + did_paint(); m_need_full_invalidation = false; return; } - Rect invalidation_rect; + Rect painted_rect; for (int i = 0; i < m_rows; ++i) { - if (line(i).needs_invalidation) - invalidation_rect = invalidation_rect.united(row_rect(i)); + if (line(i).did_paint) + painted_rect = painted_rect.united(row_rect(i)); } - invalidate_window(invalidation_rect); + did_paint(painted_rect); } -void Terminal::invalidate_window(const Rect& a_rect) +void Terminal::did_paint(const Rect& a_rect) { GUI_Rect rect = a_rect; - int rc = gui_invalidate_window(m_window_id, a_rect.is_null() ? nullptr : &rect); + int rc = gui_notify_paint_finished(m_window_id, a_rect.is_null() ? nullptr : &rect); + if (rc < 0) { + perror("gui_notify_paint_finished"); + exit(1); + } +} + +void Terminal::update() +{ + Rect rect; + for (int i = 0; i < m_rows; ++i) { + if (line(i).did_paint) + rect = rect.united(row_rect(i)); + } + GUI_Rect gui_rect = rect; + int rc = gui_invalidate_window(m_window_id, rect.is_null() ? nullptr : &gui_rect); if (rc < 0) { perror("gui_invalidate_window"); exit(1); @@ -695,7 +710,7 @@ void Terminal::set_in_active_window(bool b) return; m_in_active_window = b; invalidate_cursor(); - paint(); + update(); } void Terminal::invalidate_cursor() diff --git a/Terminal/Terminal.h b/Terminal/Terminal.h index 3c8f6a2a1f..ed43ac5e8b 100644 --- a/Terminal/Terminal.h +++ b/Terminal/Terminal.h @@ -18,6 +18,7 @@ public: void on_char(byte); void set_in_active_window(bool); + void update(); private: Font& font() { return *m_font; } @@ -25,6 +26,7 @@ private: void set_cursor(unsigned row, unsigned column); void put_character_at(unsigned row, unsigned column, byte ch); void invalidate_cursor(); + void did_paint(const Rect& = Rect()); void invalidate_window(const Rect& = Rect()); void set_window_title(const String&); @@ -67,7 +69,7 @@ private: bool has_only_one_background_color() const; byte* characters { nullptr }; Attribute* attributes { nullptr }; - bool needs_invalidation { false }; + bool did_paint { false }; bool dirty { false }; word length { 0 }; }; diff --git a/Terminal/main.cpp b/Terminal/main.cpp index 6242246cf2..34a3b7cd5a 100644 --- a/Terminal/main.cpp +++ b/Terminal/main.cpp @@ -77,7 +77,7 @@ int main(int, char**) Terminal terminal; terminal.create_window(); - terminal.paint(); + terminal.update(); for (;;) { fd_set rfds; @@ -100,7 +100,7 @@ int main(int, char**) assert(nread != 0); for (ssize_t i = 0; i < nread; ++i) terminal.on_char(buffer[i]); - terminal.paint(); + terminal.update(); } if (FD_ISSET(event_fd, &rfds)) { diff --git a/Userland/guitest.cpp b/Userland/guitest.cpp index b6a0401f42..882fe6c4dc 100644 --- a/Userland/guitest.cpp +++ b/Userland/guitest.cpp @@ -8,7 +8,7 @@ #include <Kernel/Syscall.h> #include <SharedGraphics/GraphicsBitmap.h> #include <SharedGraphics/Painter.h> -#include "gui.h" +#include <LibC/gui.h> static void paint(GraphicsBitmap& bitmap, int width, int height); @@ -68,8 +68,12 @@ int main(int argc, char** argv) case GUI_Event::Type::WindowDeactivated: dbgprintf("WID=%x WindowDeactivated\n", event.window_id); break; } - if (event.type == GUI_Event::Type::MouseDown) { + if (event.type == GUI_Event::Type::Paint) { paint(*bitmap, backing.size.width, backing.size.height); + gui_notify_paint_finished(window_id, nullptr); + } + + if (event.type == GUI_Event::Type::MouseDown) { gui_invalidate_window(window_id, nullptr); } diff --git a/WindowServer/WSEventLoop.cpp b/WindowServer/WSEventLoop.cpp index 948a103881..29aa34b9ca 100644 --- a/WindowServer/WSEventLoop.cpp +++ b/WindowServer/WSEventLoop.cpp @@ -94,6 +94,21 @@ void WSEventLoop::post_event(WSEventReceiver* receiver, OwnPtr<WSEvent>&& event) } } + if (event->type() == WSEvent::Paint) { + auto& invalidation_event = static_cast<WSPaintEvent&>(*event); + for (auto& queued_event : m_queued_events) { + if (receiver == queued_event.receiver && queued_event.event->type() == WSEvent::Paint) { + auto& queued_invalidation_event = static_cast<WSPaintEvent&>(*queued_event.event); + if (queued_invalidation_event.rect().is_empty() || queued_invalidation_event.rect().contains(invalidation_event.rect())) { +#ifdef WSEVENTLOOP_DEBUG + dbgprintf("Swallow WM_Paint\n"); +#endif + return; + } + } + } + } + m_queued_events.append({ receiver, move(event) }); if (current != m_server_process) |