1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:07:34 +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:
Andreas Kling 2019-01-24 23:40:12 +01:00
parent ccf3fc4618
commit 86eae0f8df
22 changed files with 244 additions and 102 deletions

View file

@ -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())

View file

@ -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;

View file

@ -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;
};

View file

@ -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))