1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 15:07:45 +00:00

Rework the rendering model so that clients instantiate backing stores.

This makes interactive resizing work a lot better, althought it's still not
perfect. There are still glitches and unpleasant flashes of zeroed memory.
This commit is contained in:
Andreas Kling 2019-02-20 21:59:13 +01:00
parent e0b81ee4c9
commit fa02d2a39b
17 changed files with 185 additions and 46 deletions

View file

@ -760,3 +760,9 @@ void Terminal::force_repaint()
m_need_full_flush = true; m_need_full_flush = true;
update(); update();
} }
void Terminal::resize_event(GResizeEvent&)
{
m_needs_background_fill = true;
force_repaint();
}

View file

@ -24,6 +24,7 @@ public:
private: private:
virtual void event(GEvent&) override; virtual void event(GEvent&) override;
virtual void paint_event(GPaintEvent&) override; virtual void paint_event(GPaintEvent&) override;
virtual void resize_event(GResizeEvent&) override;
virtual void keydown_event(GKeyEvent&) override; virtual void keydown_event(GKeyEvent&) override;
virtual const char* class_name() const override { return "Terminal"; } virtual const char* class_name() const override { return "Terminal"; }

View file

@ -78,8 +78,11 @@ int GEventLoop::exec()
for (;;) { for (;;) {
if (m_exit_requested) if (m_exit_requested)
return m_exit_code; return m_exit_code;
if (m_queued_events.is_empty()) process_unprocessed_messages();
if (m_queued_events.is_empty()) {
wait_for_event(); wait_for_event();
process_unprocessed_messages();
}
Vector<QueuedEvent> events = move(m_queued_events); Vector<QueuedEvent> events = move(m_queued_events);
for (auto& queued_event : events) { for (auto& queued_event : events) {
auto* receiver = queued_event.receiver; auto* receiver = queued_event.receiver;
@ -223,6 +226,7 @@ void GEventLoop::wait_for_event()
struct timeval timeout = { 0, 0 }; struct timeval timeout = { 0, 0 };
if (!m_timers.is_empty()) if (!m_timers.is_empty())
get_next_timer_expiration(timeout); get_next_timer_expiration(timeout);
ASSERT(m_unprocessed_messages.is_empty());
int rc = select(max_fd + 1, &rfds, &wfds, nullptr, (m_queued_events.is_empty() && m_timers.is_empty()) ? nullptr : &timeout); int rc = select(max_fd + 1, &rfds, &wfds, nullptr, (m_queued_events.is_empty() && m_timers.is_empty()) ? nullptr : &timeout);
if (rc < 0) { if (rc < 0) {
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
@ -260,9 +264,16 @@ void GEventLoop::wait_for_event()
bool success = drain_messages_from_server(); bool success = drain_messages_from_server();
ASSERT(success); ASSERT(success);
}
void GEventLoop::process_unprocessed_messages()
{
auto unprocessed_events = move(m_unprocessed_messages); auto unprocessed_events = move(m_unprocessed_messages);
for (auto& event : unprocessed_events) { for (auto& event : unprocessed_events) {
if (event.type == WSAPI_ServerMessage::Type::Greeting) {
m_server_pid = event.greeting.server_pid;
continue;
}
if (event.type == WSAPI_ServerMessage::Error) { if (event.type == WSAPI_ServerMessage::Error) {
dbgprintf("GEventLoop got error message from server\n"); dbgprintf("GEventLoop got error message from server\n");
@ -315,6 +326,9 @@ void GEventLoop::wait_for_event()
break; break;
} }
} }
if (!m_unprocessed_messages.is_empty())
process_unprocessed_messages();
} }
bool GEventLoop::drain_messages_from_server() bool GEventLoop::drain_messages_from_server()

View file

@ -39,9 +39,12 @@ public:
WSAPI_ServerMessage sync_request(const WSAPI_ClientMessage& request, WSAPI_ServerMessage::Type response_type); WSAPI_ServerMessage sync_request(const WSAPI_ClientMessage& request, WSAPI_ServerMessage::Type response_type);
pid_t server_pid() const { return m_server_pid; }
private: private:
void wait_for_event(); void wait_for_event();
bool drain_messages_from_server(); bool drain_messages_from_server();
void process_unprocessed_messages();
void handle_paint_event(const WSAPI_ServerMessage&, GWindow&); void handle_paint_event(const WSAPI_ServerMessage&, GWindow&);
void handle_resize_event(const WSAPI_ServerMessage&, GWindow&); void handle_resize_event(const WSAPI_ServerMessage&, GWindow&);
void handle_mouse_event(const WSAPI_ServerMessage&, GWindow&); void handle_mouse_event(const WSAPI_ServerMessage&, GWindow&);
@ -64,8 +67,8 @@ private:
bool m_running { false }; bool m_running { false };
bool m_exit_requested { false }; bool m_exit_requested { false };
int m_exit_code { 0 }; int m_exit_code { 0 };
int m_next_timer_id { 1 }; int m_next_timer_id { 1 };
pid_t m_server_pid { 0 };
struct EventLoopTimer { struct EventLoopTimer {
int timer_id { 0 }; int timer_id { 0 };

View file

@ -28,11 +28,14 @@ void GWidget::set_relative_rect(const Rect& rect)
{ {
if (rect == m_relative_rect) if (rect == m_relative_rect)
return; return;
if (m_relative_rect.size() != rect.size()) { bool size_changed = m_relative_rect.size() != rect.size();
auto event = make<GResizeEvent>(m_relative_rect.size(), rect.size());
GEventLoop::main().post_event(this, move(event));
}
m_relative_rect = rect; m_relative_rect = rect;
if (size_changed) {
GResizeEvent resize_event(m_relative_rect.size(), rect.size());
event(resize_event);
}
update(); update();
} }

View file

@ -169,9 +169,36 @@ void GWindow::event(GEvent& event)
return; return;
auto& paint_event = static_cast<GPaintEvent&>(event); auto& paint_event = static_cast<GPaintEvent&>(event);
auto rect = paint_event.rect(); auto rect = paint_event.rect();
if (rect.is_empty()) bool created_new_backing_store = !m_backing;
if (!m_backing) {
// NOTE: size() may change at any time since it's synchronously retrieved from the WindowServer.
ASSERT(GEventLoop::main().server_pid());
Size new_backing_store_size = size();
size_t size_in_bytes = new_backing_store_size.area() * sizeof(RGBA32);
void* buffer;
int shared_buffer_id = create_shared_buffer(GEventLoop::main().server_pid(), size_in_bytes, (void**)&buffer);
ASSERT(shared_buffer_id >= 0);
ASSERT(buffer);
ASSERT(buffer != (void*)-1);
m_backing = GraphicsBitmap::create_with_shared_buffer(
m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32,
shared_buffer_id,
new_backing_store_size, (RGBA32*)buffer);
}
if (rect.is_empty() || created_new_backing_store)
rect = m_main_widget->rect(); rect = m_main_widget->rect();
m_main_widget->event(*make<GPaintEvent>(rect)); m_main_widget->event(*make<GPaintEvent>(rect));
if (created_new_backing_store) {
WSAPI_ClientMessage message;
message.type = WSAPI_ClientMessage::Type::SetWindowBackingStore;
message.window_id = m_window_id;
message.backing.bpp = 32;
message.backing.pitch = m_backing->pitch();
message.backing.shared_buffer_id = m_backing->shared_buffer_id();
message.backing.has_alpha_channel = m_backing->has_alpha_channel();
message.backing.size = m_backing->size();
GEventLoop::main().post_message_to_server(message);
}
if (m_window_id) { if (m_window_id) {
WSAPI_ClientMessage message; WSAPI_ClientMessage message;
message.type = WSAPI_ClientMessage::Type::DidFinishPainting; message.type = WSAPI_ClientMessage::Type::DidFinishPainting;
@ -210,6 +237,7 @@ void GWindow::event(GEvent& event)
} }
if (event.type() == GEvent::Resize) { if (event.type() == GEvent::Resize) {
m_backing = nullptr;
m_pending_paint_event_rects.clear(); m_pending_paint_event_rects.clear();
m_rect_when_windowless = { { }, static_cast<GResizeEvent&>(event).size() }; m_rect_when_windowless = { { }, static_cast<GResizeEvent&>(event).size() };
m_main_widget->set_relative_rect({ { }, static_cast<GResizeEvent&>(event).size() }); m_main_widget->set_relative_rect({ { }, static_cast<GResizeEvent&>(event).size() });
@ -233,7 +261,7 @@ void GWindow::update(const Rect& a_rect)
#ifdef UPDATE_COALESCING_DEBUG #ifdef UPDATE_COALESCING_DEBUG
dbgprintf("Ignoring %s since it's contained by pending rect %s\n", a_rect.to_string().characters(), pending_rect.to_string().characters()); dbgprintf("Ignoring %s since it's contained by pending rect %s\n", a_rect.to_string().characters(), pending_rect.to_string().characters());
#endif #endif
return; //return;
} }
} }
m_pending_paint_event_rects.append(a_rect); m_pending_paint_event_rects.append(a_rect);

View file

@ -68,6 +68,8 @@ public:
const GWidget* hovered_widget() const { return m_hovered_widget.ptr(); } const GWidget* hovered_widget() const { return m_hovered_widget.ptr(); }
void set_hovered_widget(GWidget*); void set_hovered_widget(GWidget*);
GraphicsBitmap* backing() { return m_backing.ptr(); }
private: private:
virtual const char* class_name() const override { return "GWindow"; } virtual const char* class_name() const override { return "GWindow"; }

View file

@ -25,17 +25,9 @@ Painter::Painter(GraphicsBitmap& bitmap)
Painter::Painter(GWidget& widget) Painter::Painter(GWidget& widget)
: m_font(&widget.font()) : m_font(&widget.font())
{ {
WSAPI_ClientMessage request;
request.type = WSAPI_ClientMessage::Type::GetWindowBackingStore;
request.window_id = widget.window()->window_id();
auto response = GEventLoop::main().sync_request(request, WSAPI_ServerMessage::DidGetWindowBackingStore);
m_target = GraphicsBitmap::create_with_shared_buffer(
response.backing.has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32,
response.backing.shared_buffer_id,
response.backing.size);
ASSERT(m_target);
m_window = widget.window(); m_window = widget.window();
m_target = m_window->backing();
ASSERT(m_target);
m_translation.move_by(widget.window_relative_rect().location()); m_translation.move_by(widget.window_relative_rect().location());
// 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.window_relative_rect(); m_clip_rect = widget.window_relative_rect();
@ -236,7 +228,8 @@ void Painter::blit_with_opacity(const Point& position, const GraphicsBitmap& sou
byte alpha = 255 * opacity; byte alpha = 255 * opacity;
Rect dst_rect(position, src_rect.size()); Rect safe_src_rect = Rect::intersection(src_rect, source.rect());
Rect dst_rect(position, safe_src_rect.size());
dst_rect.move_by(m_translation); dst_rect.move_by(m_translation);
auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect);
if (clipped_rect.is_empty()) if (clipped_rect.is_empty())
@ -265,7 +258,8 @@ void Painter::blit_with_opacity(const Point& position, const GraphicsBitmap& sou
void Painter::blit_with_alpha(const Point& position, const GraphicsBitmap& source, const Rect& src_rect) void Painter::blit_with_alpha(const Point& position, const GraphicsBitmap& source, const Rect& src_rect)
{ {
ASSERT(source.has_alpha_channel()); ASSERT(source.has_alpha_channel());
Rect dst_rect(position, src_rect.size()); Rect safe_src_rect = Rect::intersection(src_rect, source.rect());
Rect dst_rect(position, safe_src_rect.size());
dst_rect.move_by(m_translation); dst_rect.move_by(m_translation);
auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect);
if (clipped_rect.is_empty()) if (clipped_rect.is_empty())
@ -298,7 +292,9 @@ void Painter::blit(const Point& position, const GraphicsBitmap& source, const Re
{ {
if (source.has_alpha_channel()) if (source.has_alpha_channel())
return blit_with_alpha(position, source, src_rect); return blit_with_alpha(position, source, src_rect);
Rect dst_rect(position, src_rect.size()); auto safe_src_rect = Rect::intersection(src_rect, source.rect());
ASSERT(source.rect().contains(safe_src_rect));
Rect dst_rect(position, safe_src_rect.size());
dst_rect.move_by(m_translation); dst_rect.move_by(m_translation);
auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect); auto clipped_rect = Rect::intersection(dst_rect, m_clip_rect);
if (clipped_rect.is_empty()) if (clipped_rect.is_empty())

View file

@ -84,6 +84,7 @@ struct WSAPI_ServerMessage {
DidGetWindowTitle, DidGetWindowTitle,
DidGetWindowRect, DidGetWindowRect,
DidGetWindowBackingStore, DidGetWindowBackingStore,
Greeting,
}; };
Type type { Invalid }; Type type { Invalid };
int window_id { -1 }; int window_id { -1 };
@ -91,6 +92,9 @@ struct WSAPI_ServerMessage {
char text[256]; char text[256];
union { union {
struct {
int server_pid;
} greeting;
struct { struct {
WSAPI_Rect rect; WSAPI_Rect rect;
WSAPI_Rect old_rect; WSAPI_Rect old_rect;
@ -148,6 +152,7 @@ struct WSAPI_ClientMessage {
GetWindowBackingStore, GetWindowBackingStore,
SetGlobalCursorTracking, SetGlobalCursorTracking,
SetWindowOpacity, SetWindowOpacity,
SetWindowBackingStore,
}; };
Type type { Invalid }; Type type { Invalid };
int window_id { -1 }; int window_id { -1 };
@ -166,6 +171,13 @@ struct WSAPI_ClientMessage {
bool has_alpha_channel; bool has_alpha_channel;
float opacity; float opacity;
} window; } window;
struct {
WSAPI_Size size;
size_t bpp;
size_t pitch;
int shared_buffer_id;
bool has_alpha_channel;
} backing;
}; };
}; };

View file

@ -44,6 +44,11 @@ WSClientConnection::WSClientConnection(int fd)
if (!s_connections) if (!s_connections)
s_connections = new HashMap<int, WSClientConnection*>; s_connections = new HashMap<int, WSClientConnection*>;
s_connections->set(m_client_id, this); s_connections->set(m_client_id, this);
WSAPI_ServerMessage message;
message.type = WSAPI_ServerMessage::Type::Greeting;
message.greeting.server_pid = getpid();
post_message(message);
} }
WSClientConnection::~WSClientConnection() WSClientConnection::~WSClientConnection()
@ -358,7 +363,13 @@ void WSClientConnection::handle_request(WSAPIDidFinishPaintingNotification& requ
return; return;
} }
auto& window = *(*it).value; auto& window = *(*it).value;
if (!window.has_painted_since_last_resize()) {
if (window.last_lazy_resize_rect().size() == request.rect().size()) {
window.set_has_painted_since_last_resize(true); window.set_has_painted_since_last_resize(true);
WSMessageLoop::the().post_message(&window, make<WSResizeEvent>(window.last_lazy_resize_rect(), window.rect()));
}
}
WSWindowManager::the().invalidate(window, request.rect()); WSWindowManager::the().invalidate(window, request.rect());
} }
@ -371,7 +382,7 @@ void WSClientConnection::handle_request(WSAPIGetWindowBackingStoreRequest& reque
return; return;
} }
auto& window = *(*it).value; auto& window = *(*it).value;
auto* backing_store = window.backing(); auto* backing_store = window.backing_store();
WSAPI_ServerMessage response; WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidGetWindowBackingStore; response.type = WSAPI_ServerMessage::Type::DidGetWindowBackingStore;
@ -384,6 +395,25 @@ void WSClientConnection::handle_request(WSAPIGetWindowBackingStoreRequest& reque
post_message(response); post_message(response);
} }
void WSClientConnection::handle_request(WSAPISetWindowBackingStoreRequest& request)
{
int window_id = request.window_id();
auto it = m_windows.find(window_id);
if (it == m_windows.end()) {
post_error("Bad window ID");
return;
}
auto& window = *(*it).value;
auto backing_store = GraphicsBitmap::create_with_shared_buffer(
request.has_alpha_channel() ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32,
request.shared_buffer_id(),
request.size());
if (!backing_store)
return;
window.set_backing_store(move(backing_store));
window.invalidate();
}
void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& request) void WSClientConnection::handle_request(WSAPISetGlobalCursorTrackingRequest& request)
{ {
int window_id = request.window_id(); int window_id = request.window_id();
@ -437,6 +467,8 @@ void WSClientConnection::on_request(WSAPIClientRequest& request)
return handle_request(static_cast<WSAPISetGlobalCursorTrackingRequest&>(request)); return handle_request(static_cast<WSAPISetGlobalCursorTrackingRequest&>(request));
case WSMessage::APISetWindowOpacityRequest: case WSMessage::APISetWindowOpacityRequest:
return handle_request(static_cast<WSAPISetWindowOpacityRequest&>(request)); return handle_request(static_cast<WSAPISetWindowOpacityRequest&>(request));
case WSMessage::APISetWindowBackingStoreRequest:
return handle_request(static_cast<WSAPISetWindowBackingStoreRequest&>(request));
default: default:
break; break;
} }

View file

@ -51,6 +51,7 @@ private:
void handle_request(WSAPIInvalidateRectRequest&); void handle_request(WSAPIInvalidateRectRequest&);
void handle_request(WSAPIDidFinishPaintingNotification&); void handle_request(WSAPIDidFinishPaintingNotification&);
void handle_request(WSAPIGetWindowBackingStoreRequest&); void handle_request(WSAPIGetWindowBackingStoreRequest&);
void handle_request(WSAPISetWindowBackingStoreRequest&);
void handle_request(WSAPISetGlobalCursorTrackingRequest&); void handle_request(WSAPISetGlobalCursorTrackingRequest&);
void handle_request(WSAPISetWindowOpacityRequest&); void handle_request(WSAPISetWindowOpacityRequest&);

View file

@ -76,8 +76,8 @@ WSWindow& WSMenu::ensure_menu_window()
void WSMenu::draw() void WSMenu::draw()
{ {
ASSERT(menu_window()); ASSERT(menu_window());
ASSERT(menu_window()->backing()); ASSERT(menu_window()->backing_store());
Painter painter(*menu_window()->backing()); Painter painter(*menu_window()->backing_store());
Rect rect { { }, menu_window()->size() }; Rect rect { { }, menu_window()->size() };
painter.draw_rect(rect, Color::White); painter.draw_rect(rect, Color::White);

View file

@ -43,6 +43,7 @@ public:
APIGetWindowBackingStoreRequest, APIGetWindowBackingStoreRequest,
APISetGlobalCursorTrackingRequest, APISetGlobalCursorTrackingRequest,
APISetWindowOpacityRequest, APISetWindowOpacityRequest,
APISetWindowBackingStoreRequest,
__End_API_Client_Requests, __End_API_Client_Requests,
}; };
@ -277,6 +278,38 @@ private:
float m_opacity { 0 }; float m_opacity { 0 };
}; };
class WSAPISetWindowBackingStoreRequest final : public WSAPIClientRequest {
public:
explicit WSAPISetWindowBackingStoreRequest(int client_id, int window_id, int shared_buffer_id, const Size& size, size_t bpp, size_t pitch, bool has_alpha_channel)
: WSAPIClientRequest(WSMessage::APISetWindowBackingStoreRequest, client_id)
, m_client_id(client_id)
, m_window_id(window_id)
, m_shared_buffer_id(shared_buffer_id)
, m_size(size)
, m_bpp(bpp)
, m_pitch(pitch)
, m_has_alpha_channel(has_alpha_channel)
{
}
int client_id() const { return m_client_id; }
int window_id() const { return m_window_id; }
int shared_buffer_id() const { return m_shared_buffer_id; }
Size size() const { return m_size; }
size_t bpp() const { return m_bpp; }
size_t pitch() const { return m_pitch; }
bool has_alpha_channel() const { return m_has_alpha_channel; }
private:
int m_client_id { 0 };
int m_window_id { 0 };
int m_shared_buffer_id { 0 };
Size m_size;
size_t m_bpp;
size_t m_pitch;
bool m_has_alpha_channel;
};
class WSAPISetWindowRectRequest final : public WSAPIClientRequest { class WSAPISetWindowRectRequest final : public WSAPIClientRequest {
public: public:
explicit WSAPISetWindowRectRequest(int client_id, int window_id, const Rect& rect) explicit WSAPISetWindowRectRequest(int client_id, int window_id, const Rect& rect)

View file

@ -330,6 +330,9 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
case WSAPI_ClientMessage::Type::GetWindowBackingStore: case WSAPI_ClientMessage::Type::GetWindowBackingStore:
post_message(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id)); post_message(client, make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id));
break; break;
case WSAPI_ClientMessage::Type::SetWindowBackingStore:
post_message(client, make<WSAPISetWindowBackingStoreRequest>(client_id, message.window_id, message.backing.shared_buffer_id, message.backing.size, message.backing.bpp, message.backing.pitch, message.backing.has_alpha_channel));
break;
case WSAPI_ClientMessage::Type::SetGlobalCursorTracking: case WSAPI_ClientMessage::Type::SetGlobalCursorTracking:
post_message(client, make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.window_id, message.value)); post_message(client, make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.window_id, message.value));
break; break;

View file

@ -36,18 +36,13 @@ void WSWindow::set_title(String&& title)
void WSWindow::set_rect(const Rect& rect) void WSWindow::set_rect(const Rect& rect)
{ {
Rect old_rect; Rect old_rect;
if (!m_client && !m_menu) ASSERT(m_client || m_menu);
return;
if (m_rect == rect) if (m_rect == rect)
return; return;
old_rect = m_rect; old_rect = m_rect;
m_rect = rect; m_rect = rect;
if (!m_backing || old_rect.size() != rect.size()) { if (m_menu && (!m_backing_store || old_rect.size() != rect.size())) {
if (m_menu) m_backing_store = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, m_rect.size());
m_backing = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, m_rect.size());
else if (m_client) {
m_backing = m_client->create_shared_bitmap(m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32, m_rect.size());
}
} }
WSWindowManager::the().notify_rect_changed(*this, old_rect, rect); WSWindowManager::the().notify_rect_changed(*this, old_rect, rect);
} }

View file

@ -55,7 +55,8 @@ public:
virtual void on_message(WSMessage&) override; virtual void on_message(WSMessage&) override;
GraphicsBitmap* backing() { return m_backing.ptr(); } GraphicsBitmap* backing_store() { return m_backing_store.ptr(); }
void set_backing_store(RetainPtr<GraphicsBitmap>&& backing_store) { m_backing_store = move(backing_store); }
void set_global_cursor_tracking_enabled(bool); void set_global_cursor_tracking_enabled(bool);
bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; } bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; }
@ -63,8 +64,11 @@ public:
bool has_alpha_channel() const { return m_has_alpha_channel; } bool has_alpha_channel() const { return m_has_alpha_channel; }
void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; } void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; }
void set_has_painted_since_last_resize(bool b) { m_has_painted_since_last_resize = b; } void set_last_lazy_resize_rect(const Rect& rect) { m_last_lazy_resize_rect = rect; }
Rect last_lazy_resize_rect() const { return m_last_lazy_resize_rect; }
bool has_painted_since_last_resize() const { return m_has_painted_since_last_resize; } bool has_painted_since_last_resize() const { return m_has_painted_since_last_resize; }
void set_has_painted_since_last_resize(bool b) { m_has_painted_since_last_resize = b; }
// For InlineLinkedList. // For InlineLinkedList.
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that. // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
@ -81,7 +85,8 @@ private:
bool m_has_alpha_channel { false }; bool m_has_alpha_channel { false };
bool m_has_painted_since_last_resize { false }; bool m_has_painted_since_last_resize { false };
WSMenu* m_menu { nullptr }; WSMenu* m_menu { nullptr };
RetainPtr<GraphicsBitmap> m_backing; RetainPtr<GraphicsBitmap> m_backing_store;
int m_window_id { -1 }; int m_window_id { -1 };
float m_opacity { 1 }; float m_opacity { 1 };
Rect m_last_lazy_resize_rect;
}; };

View file

@ -22,6 +22,7 @@
//#define DEBUG_COUNTERS //#define DEBUG_COUNTERS
//#define DEBUG_WID_IN_TITLE_BAR //#define DEBUG_WID_IN_TITLE_BAR
#define RESIZE_DEBUG #define RESIZE_DEBUG
#define USE_WALLPAPER
static const int window_titlebar_height = 16; static const int window_titlebar_height = 16;
@ -175,8 +176,10 @@ WSWindowManager::WSWindowManager()
m_cursor_bitmap_inner = CharacterBitmap::create_from_ascii(cursor_bitmap_inner_ascii, 12, 17); m_cursor_bitmap_inner = CharacterBitmap::create_from_ascii(cursor_bitmap_inner_ascii, 12, 17);
m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17); m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17);
#ifdef USE_WALLPAPER
m_wallpaper_path = "/res/wallpapers/cool.rgb"; m_wallpaper_path = "/res/wallpapers/cool.rgb";
m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 }); m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 });
#endif
#ifdef KERNEL #ifdef KERNEL
ProcFS::the().add_sys_bool("wm_flash_flush", m_flash_flush); ProcFS::the().add_sys_bool("wm_flash_flush", m_flash_flush);
@ -495,6 +498,7 @@ void WSWindowManager::start_window_resize(WSWindow& window, WSMouseEvent& event)
m_resize_window = window.make_weak_ptr();; m_resize_window = window.make_weak_ptr();;
m_resize_origin = event.position(); m_resize_origin = event.position();
m_resize_window_original_rect = window.rect(); m_resize_window_original_rect = window.rect();
m_resize_window->set_has_painted_since_last_resize(true);
invalidate(window); invalidate(window);
} }
@ -532,6 +536,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& event_
printf("[WM] Finish resizing WSWindow{%p}\n", m_resize_window.ptr()); printf("[WM] Finish resizing WSWindow{%p}\n", m_resize_window.ptr());
#endif #endif
WSMessageLoop::the().post_message(m_resize_window.ptr(), make<WSResizeEvent>(m_resize_window->rect(), m_resize_window->rect())); WSMessageLoop::the().post_message(m_resize_window.ptr(), make<WSResizeEvent>(m_resize_window->rect(), m_resize_window->rect()));
invalidate(*m_resize_window);
m_resize_window = nullptr; m_resize_window = nullptr;
return; return;
} }
@ -541,20 +546,20 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& event_
int dx = event.x() - m_resize_origin.x(); int dx = event.x() - m_resize_origin.x();
int dy = event.y() - m_resize_origin.y(); int dy = event.y() - m_resize_origin.y();
auto new_rect = m_resize_window_original_rect; auto new_rect = m_resize_window_original_rect;
new_rect.set_width(new_rect.width() + dx); new_rect.set_width(max(50, new_rect.width() + dx));
new_rect.set_height(new_rect.height() + dy); new_rect.set_height(max(50, new_rect.height() + dy));
if (m_resize_window->rect() == new_rect)
return;
#ifdef RESIZE_DEBUG #ifdef RESIZE_DEBUG
dbgprintf("[WM] Resizing [original: %s] now: %s\n", dbgprintf("[WM] Resizing [original: %s] now: %s\n",
m_resize_window_original_rect.to_string().characters(), m_resize_window_original_rect.to_string().characters(),
new_rect.to_string().characters()); new_rect.to_string().characters());
#endif #endif
if (new_rect.width() < 50)
new_rect.set_width(50);
if (new_rect.height() < 50)
new_rect.set_height(50);
m_resize_window->set_rect(new_rect); m_resize_window->set_rect(new_rect);
if (m_resize_window->has_painted_since_last_resize()) { if (m_resize_window->has_painted_since_last_resize()) {
m_resize_window->set_has_painted_since_last_resize(false); m_resize_window->set_has_painted_since_last_resize(false);
dbgprintf("I'm gonna wait for %s\n", new_rect.to_string().characters());
m_resize_window->set_last_lazy_resize_rect(new_rect);
WSMessageLoop::the().post_message(m_resize_window.ptr(), make<WSResizeEvent>(old_rect, new_rect)); WSMessageLoop::the().post_message(m_resize_window.ptr(), make<WSResizeEvent>(old_rect, new_rect));
} }
return; return;
@ -709,8 +714,8 @@ void WSWindowManager::compose()
} }
for_each_visible_window_from_back_to_front([&] (WSWindow& window) { for_each_visible_window_from_back_to_front([&] (WSWindow& window) {
RetainPtr<GraphicsBitmap> backing = window.backing(); RetainPtr<GraphicsBitmap> backing_store = window.backing_store();
if (!backing) if (!backing_store)
return IterationDecision::Continue; return IterationDecision::Continue;
if (!any_dirty_rect_intersects_window(window)) if (!any_dirty_rect_intersects_window(window))
return IterationDecision::Continue; return IterationDecision::Continue;
@ -725,9 +730,9 @@ void WSWindowManager::compose()
auto dst = window.position(); auto dst = window.position();
dst.move_by(dirty_rect_in_window_coordinates.location()); dst.move_by(dirty_rect_in_window_coordinates.location());
if (window.opacity() == 1.0f) if (window.opacity() == 1.0f)
m_back_painter->blit(dst, *backing, dirty_rect_in_window_coordinates); m_back_painter->blit(dst, *backing_store, dirty_rect_in_window_coordinates);
else else
m_back_painter->blit_with_opacity(dst, *backing, dirty_rect_in_window_coordinates, window.opacity()); m_back_painter->blit_with_opacity(dst, *backing_store, dirty_rect_in_window_coordinates, window.opacity());
m_back_painter->clear_clip_rect(); m_back_painter->clear_clip_rect();
} }
m_back_painter->clear_clip_rect(); m_back_painter->clear_clip_rect();