mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 09:48:11 +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