diff options
25 files changed, 447 insertions, 146 deletions
diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp index 3c9359fbde..31a2f4720d 100644 --- a/Applications/FileManager/main.cpp +++ b/Applications/FileManager/main.cpp @@ -607,7 +607,7 @@ int run_in_windowed_mode(RefPtr<Core::ConfigFile> config, String initial_locatio }, window); - GUI::Clipboard::the().on_content_change = [&](const String& data_type) { + GUI::Clipboard::the().on_change = [&](const String& data_type) { auto current_location = directory_view.path(); paste_action->set_enabled(data_type == "file-list" && access(current_location.characters(), W_OK) == 0); }; diff --git a/Base/etc/SystemServer.ini b/Base/etc/SystemServer.ini index 6ce8893a01..0e9727be55 100644 --- a/Base/etc/SystemServer.ini +++ b/Base/etc/SystemServer.ini @@ -46,6 +46,12 @@ Priority=high KeepAlive=1 User=window +[Clipboard] +Socket=/tmp/portal/clipboard +SocketPermissions=660 +KeepAlive=1 +User=clipboard + [SystemMenu] KeepAlive=1 User=anon diff --git a/Base/etc/group b/Base/etc/group index 6aecd0e7ae..5eafd79298 100644 --- a/Base/etc/group +++ b/Base/etc/group @@ -7,4 +7,5 @@ lookup:x:10:protocol,anon protocol:x:11:anon notify:x:12:anon window:x:13:anon,notify +clipboard:x:14:anon users:x:100:anon diff --git a/Base/etc/passwd b/Base/etc/passwd index 67cf5d44b3..814e0d6f96 100644 --- a/Base/etc/passwd +++ b/Base/etc/passwd @@ -3,5 +3,6 @@ lookup:x:10:10:LookupServer,,,:/:/bin/false protocol:x:11:11:ProtocolServer,,,:/:/bin/false notify:x:12:12:NotificationServer,,,:/:/bin/false window:x:13:13:WindowServer,,,:/:/bin/false +clipboard:x:14:14:Clipboard,,,:/:/bin/false anon:x:100:100:Anonymous,,,:/home/anon:/bin/sh nona:x:200:200:Nona,,,:/home/nona:/bin/sh diff --git a/Libraries/LibGUI/Application.cpp b/Libraries/LibGUI/Application.cpp index b2d2121da9..7f7148b754 100644 --- a/Libraries/LibGUI/Application.cpp +++ b/Libraries/LibGUI/Application.cpp @@ -27,6 +27,7 @@ #include <LibCore/EventLoop.h> #include <LibGUI/Action.h> #include <LibGUI/Application.h> +#include <LibGUI/Clipboard.h> #include <LibGUI/Desktop.h> #include <LibGUI/Label.h> #include <LibGUI/MenuBar.h> @@ -54,6 +55,7 @@ Application::Application(int argc, char** argv) s_the = this; m_event_loop = make<Core::EventLoop>(); WindowServerConnection::the(); + Clipboard::initialize({}); if (argc > 0) m_invoked_as = argv[0]; for (int i = 1; i < argc; i++) { diff --git a/Libraries/LibGUI/Clipboard.cpp b/Libraries/LibGUI/Clipboard.cpp index 8663f6a365..f596df1b7a 100644 --- a/Libraries/LibGUI/Clipboard.cpp +++ b/Libraries/LibGUI/Clipboard.cpp @@ -26,11 +26,32 @@ #include <AK/Badge.h> #include <AK/SharedBuffer.h> +#include <Clipboard/ClipboardClientEndpoint.h> +#include <Clipboard/ClipboardServerEndpoint.h> #include <LibGUI/Clipboard.h> -#include <LibGUI/WindowServerConnection.h> +#include <LibIPC/ServerConnection.h> namespace GUI { +class ClipboardServerConnection : public IPC::ServerConnection<ClipboardClientEndpoint, ClipboardServerEndpoint> + , public ClipboardClientEndpoint { + C_OBJECT(ClipboardServerConnection); + +public: + virtual void handshake() override + { + auto response = send_sync<Messages::ClipboardServer::Greet>(); + set_my_client_id(response->client_id()); + } + +private: + ClipboardServerConnection() + : IPC::ServerConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>(*this, "/tmp/portal/clipboard") + { + } + virtual void handle(const Messages::ClipboardClient::ClipboardDataChanged&) override; +}; + Clipboard& Clipboard::the() { static Clipboard* s_the; @@ -39,13 +60,25 @@ Clipboard& Clipboard::the() return *s_the; } +ClipboardServerConnection* s_connection; + +static ClipboardServerConnection& connection() +{ + return *s_connection; +} + +void Clipboard::initialize(Badge<Application>) +{ + s_connection = &ClipboardServerConnection::construct().leak_ref(); +} + Clipboard::Clipboard() { } Clipboard::DataAndType Clipboard::data_and_type() const { - auto response = WindowServerConnection::the().send_sync<Messages::WindowServer::GetClipboardContents>(); + auto response = connection().send_sync<Messages::ClipboardServer::GetClipboardData>(); if (response->shbuf_id() < 0) return {}; auto shared_buffer = SharedBuffer::create_from_shbuf_id(response->shbuf_id()); @@ -53,12 +86,12 @@ Clipboard::DataAndType Clipboard::data_and_type() const dbgprintf("GUI::Clipboard::data() failed to attach to the shared buffer\n"); return {}; } - if (response->content_size() > shared_buffer->size()) { + if (response->data_size() > shared_buffer->size()) { dbgprintf("GUI::Clipboard::data() clipping contents size is greater than shared buffer size\n"); return {}; } - auto data = String((const char*)shared_buffer->data(), response->content_size()); - auto type = response->content_type(); + auto data = String((const char*)shared_buffer->data(), response->data_size()); + auto type = response->mime_type(); return { data, type }; } @@ -74,15 +107,16 @@ void Clipboard::set_data(const StringView& data, const String& type) else ((u8*)shared_buffer->data())[0] = '\0'; shared_buffer->seal(); - shared_buffer->share_with(WindowServerConnection::the().server_pid()); + shared_buffer->share_with(connection().server_pid()); - WindowServerConnection::the().send_sync<Messages::WindowServer::SetClipboardContents>(shared_buffer->shbuf_id(), data.length(), type); + connection().send_sync<Messages::ClipboardServer::SetClipboardData>(shared_buffer->shbuf_id(), data.length(), type); } -void Clipboard::did_receive_clipboard_contents_changed(Badge<WindowServerConnection>, const String& data_type) +void ClipboardServerConnection::handle(const Messages::ClipboardClient::ClipboardDataChanged& message) { - if (on_content_change) - on_content_change(data_type); + auto& clipboard = Clipboard::the(); + if (clipboard.on_change) + clipboard.on_change(message.mime_type()); } } diff --git a/Libraries/LibGUI/Clipboard.h b/Libraries/LibGUI/Clipboard.h index 5504d91d88..e04e04c8f0 100644 --- a/Libraries/LibGUI/Clipboard.h +++ b/Libraries/LibGUI/Clipboard.h @@ -47,9 +47,9 @@ public: DataAndType data_and_type() const; - void did_receive_clipboard_contents_changed(Badge<WindowServerConnection>, const String& data_type); + Function<void(const String& data_type)> on_change; - Function<void(const String& data_type)> on_content_change; + static void initialize(Badge<Application>); private: Clipboard(); diff --git a/Libraries/LibGUI/WindowServerConnection.cpp b/Libraries/LibGUI/WindowServerConnection.cpp index e960c14ca3..6041429a26 100644 --- a/Libraries/LibGUI/WindowServerConnection.cpp +++ b/Libraries/LibGUI/WindowServerConnection.cpp @@ -280,11 +280,6 @@ void WindowServerConnection::handle(const Messages::WindowClient::ScreenRectChan Desktop::the().did_receive_screen_rect({}, message.rect()); } -void WindowServerConnection::handle(const Messages::WindowClient::ClipboardContentsChanged& message) -{ - Clipboard::the().did_receive_clipboard_contents_changed({}, message.content_type()); -} - void WindowServerConnection::handle(const Messages::WindowClient::AsyncSetWallpaperFinished&) { // This is handled manually by Desktop::set_wallpaper(). diff --git a/Libraries/LibGUI/WindowServerConnection.h b/Libraries/LibGUI/WindowServerConnection.h index 9ae71a9795..1bf058c42a 100644 --- a/Libraries/LibGUI/WindowServerConnection.h +++ b/Libraries/LibGUI/WindowServerConnection.h @@ -63,7 +63,6 @@ private: virtual void handle(const Messages::WindowClient::WindowResized&) override; virtual void handle(const Messages::WindowClient::MenuItemActivated&) override; virtual void handle(const Messages::WindowClient::ScreenRectChanged&) override; - virtual void handle(const Messages::WindowClient::ClipboardContentsChanged&) override; virtual void handle(const Messages::WindowClient::WM_WindowRemoved&) override; virtual void handle(const Messages::WindowClient::WM_WindowStateChanged&) override; virtual void handle(const Messages::WindowClient::WM_WindowIconBitmapChanged&) override; diff --git a/Services/CMakeLists.txt b/Services/CMakeLists.txt index cf18e97b48..4a2b261d06 100644 --- a/Services/CMakeLists.txt +++ b/Services/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(AudioServer) +add_subdirectory(Clipboard) add_subdirectory(DHCPClient) add_subdirectory(LaunchServer) add_subdirectory(LookupServer) diff --git a/Services/Clipboard/CMakeLists.txt b/Services/Clipboard/CMakeLists.txt new file mode 100644 index 0000000000..4f0e5ab65a --- /dev/null +++ b/Services/Clipboard/CMakeLists.txt @@ -0,0 +1,13 @@ +compile_ipc(ClipboardServer.ipc ClipboardServerEndpoint.h) +compile_ipc(ClipboardClient.ipc ClipboardClientEndpoint.h) + +set(SOURCES + ClientConnection.cpp + ClipboardClientEndpoint.h + ClipboardServerEndpoint.h + Storage.cpp + main.cpp +) + +serenity_bin(Clipboard) +target_link_libraries(Clipboard LibCore LibIPC) diff --git a/Services/Clipboard/ClientConnection.cpp b/Services/Clipboard/ClientConnection.cpp new file mode 100644 index 0000000000..16b882d1e9 --- /dev/null +++ b/Services/Clipboard/ClientConnection.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <AK/Badge.h> +#include <AK/SharedBuffer.h> +#include <Clipboard/ClientConnection.h> +#include <Clipboard/ClipboardClientEndpoint.h> +#include <Clipboard/Storage.h> + +namespace Clipboard { + +static HashMap<int, RefPtr<ClientConnection>> s_connections; + +void ClientConnection::for_each_client(Function<void(ClientConnection&)> callback) +{ + for (auto& it : s_connections) { + callback(*it.value); + } +} + +ClientConnection::ClientConnection(Core::LocalSocket& socket, int client_id) + : IPC::ClientConnection<ClipboardServerEndpoint>(*this, socket, client_id) +{ + s_connections.set(client_id, *this); +} + +ClientConnection::~ClientConnection() +{ +} + +void ClientConnection::die() +{ + s_connections.remove(client_id()); +} + +OwnPtr<Messages::ClipboardServer::GreetResponse> ClientConnection::handle(const Messages::ClipboardServer::Greet&) +{ + return make<Messages::ClipboardServer::GreetResponse>(client_id()); +} + +OwnPtr<Messages::ClipboardServer::SetClipboardDataResponse> ClientConnection::handle(const Messages::ClipboardServer::SetClipboardData& message) +{ + auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id()); + if (!shared_buffer) { + did_misbehave("SetClipboardData: Bad shared buffer ID"); + return nullptr; + } + Storage::the().set_data(*shared_buffer, message.data_size(), message.mime_type()); + return make<Messages::ClipboardServer::SetClipboardDataResponse>(); +} + +OwnPtr<Messages::ClipboardServer::GetClipboardDataResponse> ClientConnection::handle(const Messages::ClipboardServer::GetClipboardData&) +{ + auto& storage = Storage::the(); + + i32 shbuf_id = -1; + if (storage.data_size()) { + // FIXME: Optimize case where an app is copy/pasting within itself. + // We can just reuse the SharedBuffer then, since it will have the same peer PID. + // It would be even nicer if a SharedBuffer could have an arbitrary number of clients.. + RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(storage.data_size()); + ASSERT(shared_buffer); + memcpy(shared_buffer->data(), storage.data(), storage.data_size()); + shared_buffer->seal(); + shared_buffer->share_with(client_pid()); + shbuf_id = shared_buffer->shbuf_id(); + + // FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them. + // After we respond to GetClipboardData, we have to wait for the client to ref the buffer on his side. + m_last_sent_buffer = move(shared_buffer); + } + return make<Messages::ClipboardServer::GetClipboardDataResponse>(shbuf_id, storage.data_size(), storage.mime_type()); +} + +void ClientConnection::notify_about_clipboard_change() +{ + post_message(Messages::ClipboardClient::ClipboardDataChanged(Storage::the().mime_type())); +} + +} diff --git a/Services/WindowServer/Clipboard.cpp b/Services/Clipboard/ClientConnection.h index 4d9db8b4bc..904b04abc1 100644 --- a/Services/WindowServer/Clipboard.cpp +++ b/Services/Clipboard/ClientConnection.h @@ -24,55 +24,34 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <WindowServer/Clipboard.h> +#pragma once -namespace WindowServer { +#include <AK/HashMap.h> +#include <Clipboard/ClipboardServerEndpoint.h> +#include <LibIPC/ClientConnection.h> -Clipboard& Clipboard::the() -{ - static Clipboard* s_the; - if (!s_the) - s_the = new Clipboard; - return *s_the; -} +namespace Clipboard { -Clipboard::Clipboard() -{ -} +class ClientConnection final : public IPC::ClientConnection<ClipboardServerEndpoint> + , public ClipboardServerEndpoint { + C_OBJECT(ClientConnection); -Clipboard::~Clipboard() -{ -} +public: + explicit ClientConnection(Core::LocalSocket&, int client_id); + virtual ~ClientConnection() override; -const u8* Clipboard::data() const -{ - if (!m_shared_buffer) - return nullptr; - return (const u8*)m_shared_buffer->data(); -} + virtual void die() override; -int Clipboard::size() const -{ - if (!m_shared_buffer) - return 0; - return m_contents_size; -} + static void for_each_client(Function<void(ClientConnection&)>); -void Clipboard::clear() -{ - m_shared_buffer = nullptr; - m_contents_size = 0; -} + void notify_about_clipboard_change(); -void Clipboard::set_data(NonnullRefPtr<SharedBuffer>&& data, int contents_size, const String& data_type) -{ - dbg() << "Clipboard::set_data <- [" << data_type << "] " << data->data() << " (" << contents_size << " bytes)"; - m_shared_buffer = move(data); - m_contents_size = contents_size; - m_data_type = data_type; +private: + virtual OwnPtr<Messages::ClipboardServer::GreetResponse> handle(const Messages::ClipboardServer::Greet&) override; + virtual OwnPtr<Messages::ClipboardServer::GetClipboardDataResponse> handle(const Messages::ClipboardServer::GetClipboardData&) override; + virtual OwnPtr<Messages::ClipboardServer::SetClipboardDataResponse> handle(const Messages::ClipboardServer::SetClipboardData&) override; - if (on_content_change) - on_content_change(); -} + RefPtr<SharedBuffer> m_last_sent_buffer; +}; } diff --git a/Services/Clipboard/ClipboardClient.ipc b/Services/Clipboard/ClipboardClient.ipc new file mode 100644 index 0000000000..4434c56f21 --- /dev/null +++ b/Services/Clipboard/ClipboardClient.ipc @@ -0,0 +1,4 @@ +endpoint ClipboardClient = 804 +{ + ClipboardDataChanged(String mime_type) =| +} diff --git a/Services/Clipboard/ClipboardServer.ipc b/Services/Clipboard/ClipboardServer.ipc new file mode 100644 index 0000000000..4b419459ec --- /dev/null +++ b/Services/Clipboard/ClipboardServer.ipc @@ -0,0 +1,7 @@ +endpoint ClipboardServer = 802 +{ + Greet() => (i32 client_id) + + GetClipboardData() => (i32 shbuf_id, i32 data_size, String mime_type) + SetClipboardData(i32 shbuf_id, i32 data_size, String mime_type) => () +} diff --git a/Services/WindowServer/Clipboard.h b/Services/Clipboard/Storage.cpp index 6cb9140234..f64b5a4f70 100644 --- a/Services/WindowServer/Clipboard.h +++ b/Services/Clipboard/Storage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,39 +24,35 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#pragma once +#include <Clipboard/Storage.h> -#include <AK/Function.h> -#include <AK/SharedBuffer.h> -#include <AK/String.h> +namespace Clipboard { -namespace WindowServer { - -class Clipboard { -public: - static Clipboard& the(); - ~Clipboard(); - - bool has_data() const - { - return m_shared_buffer; - } - - const String& data_type() const { return m_data_type; } - const u8* data() const; - int size() const; +Storage& Storage::the() +{ + static Storage* s_the; + if (!s_the) + s_the = new Storage; + return *s_the; +} - void clear(); - void set_data(NonnullRefPtr<SharedBuffer>&&, int contents_size, const String& data_type); +Storage::Storage() +{ +} - Function<void()> on_content_change; +Storage::~Storage() +{ +} -private: - Clipboard(); +void Storage::set_data(NonnullRefPtr<SharedBuffer> data, size_t data_size, const String& mime_type) +{ + dbg() << "Storage::set_data <- [" << mime_type << "] " << data->data() << " (" << data_size << " bytes)"; + m_shared_buffer = move(data); + m_data_size = data_size; + m_mime_type = mime_type; - String m_data_type; - RefPtr<SharedBuffer> m_shared_buffer; - int m_contents_size { 0 }; -}; + if (on_content_change) + on_content_change(); +} } diff --git a/Services/Clipboard/Storage.h b/Services/Clipboard/Storage.h new file mode 100644 index 0000000000..7f38c3d1db --- /dev/null +++ b/Services/Clipboard/Storage.h @@ -0,0 +1,44 @@ +#pragma once + +#include <AK/Function.h> +#include <AK/SharedBuffer.h> +#include <AK/String.h> + +namespace Clipboard { + +class Storage { +public: + static Storage& the(); + ~Storage(); + + bool has_data() const { return m_shared_buffer; } + + const String& mime_type() const { return m_mime_type; } + + const u8* data() const + { + if (!has_data()) + return nullptr; + return static_cast<const u8*>(m_shared_buffer->data()); + } + + size_t data_size() const + { + if (has_data()) + return m_data_size; + return 0; + } + + void set_data(NonnullRefPtr<SharedBuffer>, size_t data_size, const String& mime_type); + + Function<void()> on_content_change; + +private: + Storage(); + + String m_mime_type; + RefPtr<SharedBuffer> m_shared_buffer; + size_t m_data_size { 0 }; +}; + +} diff --git a/Services/Clipboard/WindowServer.ipc b/Services/Clipboard/WindowServer.ipc new file mode 100644 index 0000000000..1d678cbfb5 --- /dev/null +++ b/Services/Clipboard/WindowServer.ipc @@ -0,0 +1,97 @@ +endpoint WindowServer = 2 +{ + Greet() => (i32 client_id, Gfx::Rect screen_rect, i32 system_theme_buffer_id) + + CreateMenubar() => (i32 menubar_id) + DestroyMenubar(i32 menubar_id) => () + + CreateMenu(String menu_title) => (i32 menu_id) + DestroyMenu(i32 menu_id) => () + + AddMenuToMenubar(i32 menubar_id, i32 menu_id) => () + SetApplicationMenubar(i32 menubar_id) => () + + SetSystemMenu(i32 menu_id) => () + + AddMenuItem( + i32 menu_id, + i32 identifier, + i32 submenu_id, + String text, + bool enabled, + bool checkable, + bool checked, + String shortcut, + i32 icon_buffer_id, + bool exclusive) => () + + AddMenuSeparator(i32 menu_id) => () + + UpdateMenuItem(i32 menu_id, i32 identifier, i32 submenu_id, String text, bool enabled, bool checkable, bool checked, String shortcut) => () + + CreateWindow( + Gfx::Rect rect, + bool has_alpha_channel, + bool modal, + bool minimizable, + bool resizable, + bool fullscreen, + bool frameless, + float opacity, + Gfx::Size base_size, + Gfx::Size size_increment, + i32 type, + String title, + i32 parent_window_id) => (i32 window_id) + + DestroyWindow(i32 window_id) => (Vector<i32> destroyed_window_ids) + + SetWindowTitle(i32 window_id, String title) => () + GetWindowTitle(i32 window_id) => (String title) + + SetWindowRect(i32 window_id, Gfx::Rect rect) => (Gfx::Rect rect) + GetWindowRect(i32 window_id) => (Gfx::Rect rect) + + InvalidateRect(i32 window_id, Vector<Gfx::Rect> rects, bool ignore_occlusion) =| + DidFinishPainting(i32 window_id, Vector<Gfx::Rect> rects) =| + + SetGlobalCursorTracking(i32 window_id, bool enabled) => () + SetWindowOpacity(i32 window_id, float opacity) => () + + SetWindowBackingStore(i32 window_id, i32 bpp, i32 pitch, i32 shbuf_id, bool has_alpha_channel, Gfx::Size size, bool flush_immediately) => () + GetClipboardData() => (i32 shbuf_id, i32 content_size, String content_type) + SetClipboardData(i32 shbuf_id, i32 content_size, String content_type) => () + + WM_SetActiveWindow(i32 client_id, i32 window_id) =| + WM_SetWindowMinimized(i32 client_id, i32 window_id, bool minimized) =| + WM_StartWindowResize(i32 client_id, i32 window_id) =| + WM_PopupWindowMenu(i32 client_id, i32 window_id, Gfx::Point screen_position) =| + WM_SetWindowTaskbarRect(i32 client_id, i32 window_id, Gfx::Rect rect) =| + + SetWindowHasAlphaChannel(i32 window_id, bool has_alpha_channel) => () + MoveWindowToFront(i32 window_id) => () + SetFullscreen(i32 window_id, bool fullscreen) => () + PopupMenu(i32 menu_id, Gfx::Point screen_position) => () + DismissMenu(i32 menu_id) => () + + AsyncSetWallpaper(String path) =| + + SetBackgroundColor(String background_color) => () + SetWallpaperMode(String mode) => () + + SetResolution(Gfx::Size resolution) => (bool success, Gfx::Size resolution) + SetWindowIconBitmap(i32 window_id, Gfx::ShareableBitmap icon) => () + + GetWallpaper() => (String path) + SetWindowOverrideCursor(i32 window_id, i32 cursor_type) => () + + StartDrag(String text, String data_type, String data, i32 bitmap_id, Gfx::Size bitmap_size) => (bool started) + + SetSystemTheme(String theme_path, String theme_name) => (bool success) + GetSystemTheme() => (String theme_name) + + SetWindowBaseSizeAndSizeIncrement(i32 window_id, Gfx::Size base_size, Gfx::Size size_increment) => () + + EnableDisplayLink() =| + DisableDisplayLink() =| +} diff --git a/Services/Clipboard/main.cpp b/Services/Clipboard/main.cpp new file mode 100644 index 0000000000..18839418b8 --- /dev/null +++ b/Services/Clipboard/main.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <Clipboard/ClientConnection.h> +#include <Clipboard/Storage.h> +#include <LibCore/EventLoop.h> +#include <LibCore/LocalServer.h> +#include <LibIPC/ClientConnection.h> + +int main(int, char**) +{ + if (pledge("stdio shared_buffer accept unix rpath cpath fattr", nullptr) < 0) { + perror("pledge"); + return 1; + } + Core::EventLoop event_loop; + if (pledge("stdio shared_buffer unix accept", nullptr) < 0) { + perror("pledge"); + return 1; + } + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } + + auto server = Core::LocalServer::construct(); + bool ok = server->take_over_from_system_server(); + ASSERT(ok); + + if (pledge("stdio shared_buffer accept", nullptr) < 0) { + perror("pledge"); + return 1; + } + + server->on_ready_to_accept = [&] { + auto client_socket = server->accept(); + if (!client_socket) { + dbg() << "ProtocolServer: accept failed."; + return; + } + static int s_next_client_id = 0; + int client_id = ++s_next_client_id; + IPC::new_client_connection<Clipboard::ClientConnection>(*client_socket, client_id); + }; + + Clipboard::Storage::the().on_content_change = [&] { + Clipboard::ClientConnection::for_each_client([&](auto& client) { + client.notify_about_clipboard_change(); + }); + }; + + return event_loop.exec(); +} diff --git a/Services/WindowServer/CMakeLists.txt b/Services/WindowServer/CMakeLists.txt index af14d6aa96..b822fec6b5 100644 --- a/Services/WindowServer/CMakeLists.txt +++ b/Services/WindowServer/CMakeLists.txt @@ -5,7 +5,6 @@ set(SOURCES AppletManager.cpp Button.cpp ClientConnection.cpp - Clipboard.cpp Compositor.cpp Cursor.cpp EventLoop.cpp diff --git a/Services/WindowServer/ClientConnection.cpp b/Services/WindowServer/ClientConnection.cpp index 16827c9cd8..3b1deebc28 100644 --- a/Services/WindowServer/ClientConnection.cpp +++ b/Services/WindowServer/ClientConnection.cpp @@ -30,7 +30,6 @@ #include <LibGfx/SystemTheme.h> #include <WindowServer/AppletManager.h> #include <WindowServer/ClientConnection.h> -#include <WindowServer/Clipboard.h> #include <WindowServer/Compositor.h> #include <WindowServer/EventLoop.h> #include <WindowServer/Menu.h> @@ -112,11 +111,6 @@ void ClientConnection::notify_about_new_screen_rect(const Gfx::Rect& rect) post_message(Messages::WindowClient::ScreenRectChanged(rect)); } -void ClientConnection::notify_about_clipboard_contents_changed() -{ - post_message(Messages::WindowClient::ClipboardContentsChanged(Clipboard::the().data_type())); -} - OwnPtr<Messages::WindowServer::CreateMenubarResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenubar&) { int menubar_id = m_next_menubar_id++; @@ -417,40 +411,6 @@ OwnPtr<Messages::WindowServer::GetWindowRectResponse> ClientConnection::handle(c return make<Messages::WindowServer::GetWindowRectResponse>(it->value->rect()); } -OwnPtr<Messages::WindowServer::SetClipboardContentsResponse> ClientConnection::handle(const Messages::WindowServer::SetClipboardContents& message) -{ - auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id()); - if (!shared_buffer) { - did_misbehave("SetClipboardContents: Bad shared buffer ID"); - return nullptr; - } - Clipboard::the().set_data(*shared_buffer, message.content_size(), message.content_type()); - return make<Messages::WindowServer::SetClipboardContentsResponse>(); -} - -OwnPtr<Messages::WindowServer::GetClipboardContentsResponse> ClientConnection::handle(const Messages::WindowServer::GetClipboardContents&) -{ - auto& clipboard = Clipboard::the(); - - i32 shbuf_id = -1; - if (clipboard.size()) { - // FIXME: Optimize case where an app is copy/pasting within itself. - // We can just reuse the SharedBuffer then, since it will have the same peer PID. - // It would be even nicer if a SharedBuffer could have an arbitrary number of clients.. - RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(clipboard.size()); - ASSERT(shared_buffer); - memcpy(shared_buffer->data(), clipboard.data(), clipboard.size()); - shared_buffer->seal(); - shared_buffer->share_with(client_pid()); - shbuf_id = shared_buffer->shbuf_id(); - - // FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them. - // After we respond to GetClipboardContents, we have to wait for the client to ref the buffer on his side. - m_last_sent_clipboard_content = move(shared_buffer); - } - return make<Messages::WindowServer::GetClipboardContentsResponse>(shbuf_id, clipboard.size(), clipboard.data_type()); -} - Window* ClientConnection::window_from_id(i32 window_id) { auto it = m_windows.find(window_id); diff --git a/Services/WindowServer/ClientConnection.h b/Services/WindowServer/ClientConnection.h index 92c2f2fa08..bedcdb5e91 100644 --- a/Services/WindowServer/ClientConnection.h +++ b/Services/WindowServer/ClientConnection.h @@ -63,7 +63,6 @@ public: bool is_showing_modal_window() const; void notify_about_new_screen_rect(const Gfx::Rect&); - void notify_about_clipboard_contents_changed(); void post_paint_message(Window&, bool ignore_occlusion = false); Menu* find_menu_by_id(int menu_id) @@ -102,8 +101,6 @@ private: virtual OwnPtr<Messages::WindowServer::SetGlobalCursorTrackingResponse> handle(const Messages::WindowServer::SetGlobalCursorTracking&) override; virtual OwnPtr<Messages::WindowServer::SetWindowOpacityResponse> handle(const Messages::WindowServer::SetWindowOpacity&) override; virtual OwnPtr<Messages::WindowServer::SetWindowBackingStoreResponse> handle(const Messages::WindowServer::SetWindowBackingStore&) override; - virtual OwnPtr<Messages::WindowServer::GetClipboardContentsResponse> handle(const Messages::WindowServer::GetClipboardContents&) override; - virtual OwnPtr<Messages::WindowServer::SetClipboardContentsResponse> handle(const Messages::WindowServer::SetClipboardContents&) override; virtual void handle(const Messages::WindowServer::WM_SetActiveWindow&) override; virtual void handle(const Messages::WindowServer::WM_SetWindowMinimized&) override; virtual void handle(const Messages::WindowServer::WM_StartWindowResize&) override; @@ -141,8 +138,6 @@ private: int m_next_window_id { 1982 }; bool m_has_display_link { false }; - - RefPtr<SharedBuffer> m_last_sent_clipboard_content; }; } diff --git a/Services/WindowServer/EventLoop.cpp b/Services/WindowServer/EventLoop.cpp index 078794d6f3..45a34e9055 100644 --- a/Services/WindowServer/EventLoop.cpp +++ b/Services/WindowServer/EventLoop.cpp @@ -24,7 +24,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "Clipboard.h" #include <Kernel/KeyCode.h> #include <Kernel/MousePacket.h> #include <LibCore/LocalSocket.h> @@ -76,12 +75,6 @@ EventLoop::EventLoop() m_mouse_notifier = Core::Notifier::construct(m_mouse_fd, Core::Notifier::Read); m_mouse_notifier->on_ready_to_read = [this] { drain_mouse(); }; - - Clipboard::the().on_content_change = [&] { - ClientConnection::for_each_client([&](auto& client) { - client.notify_about_clipboard_contents_changed(); - }); - }; } EventLoop::~EventLoop() diff --git a/Services/WindowServer/WindowClient.ipc b/Services/WindowServer/WindowClient.ipc index 3c94ccf89e..ec04a2a91a 100644 --- a/Services/WindowServer/WindowClient.ipc +++ b/Services/WindowServer/WindowClient.ipc @@ -20,8 +20,6 @@ endpoint WindowClient = 4 ScreenRectChanged(Gfx::Rect rect) =| - ClipboardContentsChanged(String content_type) =| - WM_WindowRemoved(i32 wm_id, i32 client_id, i32 window_id) =| WM_WindowStateChanged(i32 wm_id, i32 client_id, i32 window_id, bool is_active, bool is_minimized, bool is_frameless, i32 window_type, String title, Gfx::Rect rect) =| WM_WindowIconBitmapChanged(i32 wm_id, i32 client_id, i32 window_id, i32 icon_buffer_id, Gfx::Size icon_size) =| diff --git a/Services/WindowServer/WindowServer.ipc b/Services/WindowServer/WindowServer.ipc index 214afa7567..8d958823a0 100644 --- a/Services/WindowServer/WindowServer.ipc +++ b/Services/WindowServer/WindowServer.ipc @@ -59,8 +59,6 @@ endpoint WindowServer = 2 SetWindowOpacity(i32 window_id, float opacity) => () SetWindowBackingStore(i32 window_id, i32 bpp, i32 pitch, i32 shbuf_id, bool has_alpha_channel, Gfx::Size size, bool flush_immediately) => () - GetClipboardContents() => (i32 shbuf_id, i32 content_size, String content_type) - SetClipboardContents(i32 shbuf_id, i32 content_size, String content_type) => () WM_SetActiveWindow(i32 client_id, i32 window_id) =| WM_SetWindowMinimized(i32 client_id, i32 window_id, bool minimized) =| |