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