From 7cfe712f4d0298cb645a602afe116698ab0fcd67 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 29 Mar 2020 19:04:05 +0200 Subject: [PATCH] LibGfx+LibIPC: Add Gfx::ShareableBitmap, a bitmap for easy IPC usage With this patch, it's now possible to pass a Gfx::ShareableBitmap in an IPC message. As long as the message itself is synchronous, the bitmap will be adopted by the receiving end, and disowned by the sender nicely without any accounting effort like we've had to do in the past. Use this in NotificationServer to allow sending arbitrary bitmaps as icons instead of paths-to-icons. --- Applications/IRCClient/IRCWindow.cpp | 2 +- DevTools/IPCCompiler/main.cpp | 5 +++ Libraries/LibGUI/DragOperation.cpp | 2 +- Libraries/LibGUI/Notification.cpp | 2 +- Libraries/LibGUI/Notification.h | 7 ++-- Libraries/LibGfx/Bitmap.cpp | 11 ++++- Libraries/LibGfx/Bitmap.h | 5 ++- Libraries/LibGfx/Forward.h | 1 + Libraries/LibGfx/Makefile | 1 + Libraries/LibGfx/ShareableBitmap.cpp | 40 +++++++++++++++++++ Libraries/LibGfx/ShareableBitmap.h | 35 ++++++++++++++++ .../NotificationServer/ClientConnection.cpp | 5 ++- Servers/NotificationServer/ClientConnection.h | 2 +- .../NotificationServer/NotificationServer.ipc | 2 +- .../NotificationServer/NotificationWindow.cpp | 7 ++-- .../NotificationServer/NotificationWindow.h | 2 +- Userland/notify.cpp | 3 +- 17 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 Libraries/LibGfx/ShareableBitmap.cpp create mode 100644 Libraries/LibGfx/ShareableBitmap.h diff --git a/Applications/IRCClient/IRCWindow.cpp b/Applications/IRCClient/IRCWindow.cpp index d1f58ab6db..8fbca5a57e 100644 --- a/Applications/IRCClient/IRCWindow.cpp +++ b/Applications/IRCClient/IRCWindow.cpp @@ -116,7 +116,7 @@ void IRCWindow::post_notification_if_needed(const String& name, const String& me notification->set_title(name); } - notification->set_icon_path("/res/icons/32x32/app-irc-client.png"); + notification->set_icon(Gfx::Bitmap::load_from_file("/res/icons/32x32/app-irc-client.png")); notification->set_text(message); notification->show(); } diff --git a/DevTools/IPCCompiler/main.cpp b/DevTools/IPCCompiler/main.cpp index b12e8328fa..252ef7dd4e 100644 --- a/DevTools/IPCCompiler/main.cpp +++ b/DevTools/IPCCompiler/main.cpp @@ -228,6 +228,7 @@ int main(int argc, char** argv) dbg() << "#include "; dbg() << "#include "; dbg() << "#include "; + dbg() << "#include "; dbg() << "#include "; dbg() << "#include "; dbg() << "#include "; @@ -362,6 +363,10 @@ int main(int argc, char** argv) dbg() << " stream << rect.width();"; dbg() << " stream << rect.height();"; dbg() << " }"; + } else if (parameter.type == "Gfx::ShareableBitmap") { + dbg() << " stream << m_" << parameter.name << ".shbuf_id();"; + dbg() << " stream << m_" << parameter.name << ".width();"; + dbg() << " stream << m_" << parameter.name << ".height();"; } else { dbg() << " stream << m_" << parameter.name << ";"; } diff --git a/Libraries/LibGUI/DragOperation.cpp b/Libraries/LibGUI/DragOperation.cpp index 2f0cb55e2f..462a9822f7 100644 --- a/Libraries/LibGUI/DragOperation.cpp +++ b/Libraries/LibGUI/DragOperation.cpp @@ -53,7 +53,7 @@ DragOperation::Outcome DragOperation::exec() Gfx::Size bitmap_size; RefPtr shared_bitmap; if (m_bitmap) { - shared_bitmap = m_bitmap->to_shareable_bitmap(); + shared_bitmap = m_bitmap->to_bitmap_backed_by_shared_buffer(); shared_bitmap->shared_buffer()->share_with(WindowServerConnection::the().server_pid()); bitmap_id = shared_bitmap->shbuf_id(); bitmap_size = shared_bitmap->size(); diff --git a/Libraries/LibGUI/Notification.cpp b/Libraries/LibGUI/Notification.cpp index af8d794d83..4b231c9d2d 100644 --- a/Libraries/LibGUI/Notification.cpp +++ b/Libraries/LibGUI/Notification.cpp @@ -35,7 +35,7 @@ Notification::~Notification() void Notification::show() { auto connection = NotificationServerConnection::construct(); - connection->post_message(Messages::NotificationServer::ShowNotification(m_text, m_title, m_icon_path)); + connection->send_sync(m_text, m_title, m_icon ? m_icon->to_shareable_bitmap(connection->server_pid()) : Gfx::ShareableBitmap()); } } diff --git a/Libraries/LibGUI/Notification.h b/Libraries/LibGUI/Notification.h index da13ca8be2..6896b963d5 100644 --- a/Libraries/LibGUI/Notification.h +++ b/Libraries/LibGUI/Notification.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace GUI { @@ -16,8 +17,8 @@ public: const String& title() const { return m_title; } void set_title(const String& title) { m_title = title; } - const String& icon_path() const { return m_icon_path; } - void set_icon_path(const String& icon_path) { m_icon_path = icon_path; } + const Gfx::Bitmap* icon() const { return m_icon; } + void set_icon(const Gfx::Bitmap* icon) { m_icon = icon; } void show(); @@ -26,7 +27,7 @@ private: String m_title; String m_text; - String m_icon_path; + RefPtr m_icon; }; } diff --git a/Libraries/LibGfx/Bitmap.cpp b/Libraries/LibGfx/Bitmap.cpp index cda0ad656b..962ea59ba9 100644 --- a/Libraries/LibGfx/Bitmap.cpp +++ b/Libraries/LibGfx/Bitmap.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -97,7 +98,7 @@ Bitmap::Bitmap(BitmapFormat format, NonnullRefPtr&& shared_buffer, ASSERT(format != BitmapFormat::Indexed8); } -NonnullRefPtr Bitmap::to_shareable_bitmap() const +NonnullRefPtr Bitmap::to_bitmap_backed_by_shared_buffer() const { if (m_shared_buffer) return *this; @@ -164,4 +165,12 @@ int Bitmap::shbuf_id() const return m_shared_buffer ? m_shared_buffer->shbuf_id() : -1; } +ShareableBitmap Bitmap::to_shareable_bitmap(pid_t peer_pid) const +{ + auto bitmap = to_bitmap_backed_by_shared_buffer(); + if (peer_pid > 0) + bitmap->shared_buffer()->share_with(peer_pid); + return ShareableBitmap(*bitmap); +} + } diff --git a/Libraries/LibGfx/Bitmap.h b/Libraries/LibGfx/Bitmap.h index be05d08cdb..7fdec97e65 100644 --- a/Libraries/LibGfx/Bitmap.h +++ b/Libraries/LibGfx/Bitmap.h @@ -30,6 +30,7 @@ #include #include #include +#include #include namespace Gfx { @@ -49,7 +50,9 @@ public: static RefPtr load_from_file(const StringView& path); static NonnullRefPtr create_with_shared_buffer(BitmapFormat, NonnullRefPtr&&, const Size&); - NonnullRefPtr to_shareable_bitmap() const; + NonnullRefPtr to_bitmap_backed_by_shared_buffer() const; + + ShareableBitmap to_shareable_bitmap(pid_t peer_pid = -1) const; ~Bitmap(); diff --git a/Libraries/LibGfx/Forward.h b/Libraries/LibGfx/Forward.h index c41c7bc21a..37946b3b43 100644 --- a/Libraries/LibGfx/Forward.h +++ b/Libraries/LibGfx/Forward.h @@ -44,6 +44,7 @@ class Palette; class PaletteImpl; class Point; class Rect; +class ShareableBitmap; class Size; class StylePainter; struct SystemTheme; diff --git a/Libraries/LibGfx/Makefile b/Libraries/LibGfx/Makefile index e02371bfe9..4c538660c7 100644 --- a/Libraries/LibGfx/Makefile +++ b/Libraries/LibGfx/Makefile @@ -12,6 +12,7 @@ OBJS = \ Palette.o \ Point.o \ Rect.o \ + ShareableBitmap.o \ Size.o \ StylePainter.o \ SystemTheme.o \ diff --git a/Libraries/LibGfx/ShareableBitmap.cpp b/Libraries/LibGfx/ShareableBitmap.cpp new file mode 100644 index 0000000000..ad5fe8dacd --- /dev/null +++ b/Libraries/LibGfx/ShareableBitmap.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +namespace Gfx { + +ShareableBitmap::ShareableBitmap(const Bitmap& bitmap) + : m_bitmap(bitmap.to_bitmap_backed_by_shared_buffer()) +{ +} + +} + +namespace IPC { + +bool decode(Decoder& decoder, Gfx::ShareableBitmap& shareable_bitmap) +{ + i32 shbuf_id = 0; + Gfx::Size size; + if (!decoder.decode(shbuf_id)) + return false; + if (!decoder.decode(size)) + return false; + + if (shbuf_id == -1) + return true; + + dbg() << "Decoding a ShareableBitmap with shbuf_id=" << shbuf_id << ", size=" << size; + + auto shared_buffer = SharedBuffer::create_from_shbuf_id(shbuf_id); + if (!shared_buffer) + return false; + + auto bitmap = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, shared_buffer.release_nonnull(), size); + shareable_bitmap = bitmap->to_shareable_bitmap(); + return true; +} + +} diff --git a/Libraries/LibGfx/ShareableBitmap.h b/Libraries/LibGfx/ShareableBitmap.h new file mode 100644 index 0000000000..498ab64c37 --- /dev/null +++ b/Libraries/LibGfx/ShareableBitmap.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +namespace Gfx { + +class ShareableBitmap { +public: + ShareableBitmap() {} + explicit ShareableBitmap(const Gfx::Bitmap&); + + bool is_valid() const { return m_bitmap; } + + i32 shbuf_id() const { return m_bitmap ? m_bitmap->shbuf_id() : -1; } + + const Bitmap* bitmap() const { return m_bitmap; } + Bitmap* bitmap() { return m_bitmap; } + + Size size() const { return m_bitmap ? m_bitmap->size() : Size(); } + Rect rect() const { return m_bitmap ? m_bitmap->rect() : Rect(); } + + int width() const { return size().width(); } + int height() const { return size().height(); } + +private: + RefPtr m_bitmap; +}; + +} + +namespace IPC { +bool decode(Decoder&, Gfx::ShareableBitmap&); +} diff --git a/Servers/NotificationServer/ClientConnection.cpp b/Servers/NotificationServer/ClientConnection.cpp index c61d1cc028..9b8064de03 100644 --- a/Servers/NotificationServer/ClientConnection.cpp +++ b/Servers/NotificationServer/ClientConnection.cpp @@ -53,10 +53,11 @@ OwnPtr ClientConnection::handle(con return make(client_id()); } -void ClientConnection::handle(const Messages::NotificationServer::ShowNotification& message) +OwnPtr ClientConnection::handle(const Messages::NotificationServer::ShowNotification& message) { - auto window = NotificationWindow::construct(message.text(), message.title(), message.icon_path()); + auto window = NotificationWindow::construct(message.text(), message.title(), message.icon()); window->show(); + return make(); } } diff --git a/Servers/NotificationServer/ClientConnection.h b/Servers/NotificationServer/ClientConnection.h index 93493679c8..bec07fb127 100644 --- a/Servers/NotificationServer/ClientConnection.h +++ b/Servers/NotificationServer/ClientConnection.h @@ -43,7 +43,7 @@ private: explicit ClientConnection(Core::LocalSocket&, int client_id); virtual OwnPtr handle(const Messages::NotificationServer::Greet&) override; - virtual void handle(const Messages::NotificationServer::ShowNotification&) override; + virtual OwnPtr handle(const Messages::NotificationServer::ShowNotification&) override; }; } diff --git a/Servers/NotificationServer/NotificationServer.ipc b/Servers/NotificationServer/NotificationServer.ipc index 75bf5e0f89..f1ac5e13df 100644 --- a/Servers/NotificationServer/NotificationServer.ipc +++ b/Servers/NotificationServer/NotificationServer.ipc @@ -3,5 +3,5 @@ endpoint NotificationServer = 95 // Basic protocol Greet() => (i32 client_id) - ShowNotification(String text, String title, String icon_path) =| + ShowNotification(String text, String title, Gfx::ShareableBitmap icon) => () } diff --git a/Servers/NotificationServer/NotificationWindow.cpp b/Servers/NotificationServer/NotificationWindow.cpp index 42915f65f9..614075701c 100644 --- a/Servers/NotificationServer/NotificationWindow.cpp +++ b/Servers/NotificationServer/NotificationWindow.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace NotificationServer { @@ -55,7 +56,7 @@ void update_notification_window_locations() } } -NotificationWindow::NotificationWindow(const String& text, const String& title, const String& icon_path) +NotificationWindow::NotificationWindow(const String& text, const String& title, const Gfx::ShareableBitmap& icon) { s_windows.append(this); @@ -86,11 +87,11 @@ NotificationWindow::NotificationWindow(const String& text, const String& title, widget.layout()->set_margins({ 8, 8, 8, 8 }); widget.layout()->set_spacing(6); - if (auto icon = Gfx::Bitmap::load_from_file(icon_path)) { + if (icon.is_valid()) { auto& icon_label = widget.add(); icon_label.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); icon_label.set_preferred_size(32, 32); - icon_label.set_icon(icon); + icon_label.set_icon(icon.bitmap()); } auto& left_container = widget.add(); diff --git a/Servers/NotificationServer/NotificationWindow.h b/Servers/NotificationServer/NotificationWindow.h index 232588ff60..3519af0752 100644 --- a/Servers/NotificationServer/NotificationWindow.h +++ b/Servers/NotificationServer/NotificationWindow.h @@ -38,7 +38,7 @@ public: void set_original_rect(Gfx::Rect original_rect) { m_original_rect = original_rect; }; private: - NotificationWindow(const String& text, const String& title, const String& icon_path); + NotificationWindow(const String& text, const String& title, const Gfx::ShareableBitmap&); Gfx::Rect m_original_rect; }; diff --git a/Userland/notify.cpp b/Userland/notify.cpp index 4dded943f5..37431e00ee 100644 --- a/Userland/notify.cpp +++ b/Userland/notify.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include int main(int argc, char** argv) @@ -45,7 +46,7 @@ int main(int argc, char** argv) auto notification = GUI::Notification::construct(); notification->set_text(message); notification->set_title(title); - notification->set_icon_path(icon_path); + notification->set_icon(Gfx::Bitmap::load_from_file(icon_path)); notification->show(); return 0;