summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Process.h1
-rw-r--r--Kernel/ProcessGUI.cpp42
-rw-r--r--Kernel/Syscall.cpp2
-rw-r--r--Kernel/Syscall.h1
-rw-r--r--LibC/gui.cpp6
-rw-r--r--LibC/gui.h1
-rw-r--r--LibGUI/GEventLoop.cpp2
-rw-r--r--LibGUI/GWidget.cpp2
-rw-r--r--LibGUI/GWindow.cpp17
-rw-r--r--LibGUI/GWindow.h3
-rw-r--r--SharedGraphics/GraphicsBitmap.cpp10
-rw-r--r--Terminal/Terminal.cpp39
-rw-r--r--Terminal/Terminal.h4
-rw-r--r--Terminal/main.cpp4
-rw-r--r--Userland/guitest.cpp8
-rw-r--r--WindowServer/WSEventLoop.cpp15
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)