diff --git a/Userland/Services/SpiceAgent/Message.cpp b/Userland/Services/SpiceAgent/Message.cpp index 6b2bed27364..ecf399030ec 100644 --- a/Userland/Services/SpiceAgent/Message.cpp +++ b/Userland/Services/SpiceAgent/Message.cpp @@ -52,4 +52,37 @@ ErrorOr AnnounceCapabilitiesMessage::debug_description() return builder.to_string(); } +ErrorOr ClipboardGrabMessage::read_from_stream(AK::Stream& stream) +{ + auto types = Vector(); + while (!stream.is_eof()) { + auto value = TRY(stream.read_value()); + if (value >= to_underlying(ClipboardDataType::__End)) { + return Error::from_string_literal("Unsupported clipboard type"); + } + + types.append(static_cast(value)); + } + + return ClipboardGrabMessage(types); +} + +ErrorOr ClipboardGrabMessage::write_to_stream(AK::Stream& stream) +{ + for (auto type : types()) { + TRY(stream.write_value(type)); + } + + return {}; +} + +ErrorOr ClipboardGrabMessage::debug_description() +{ + StringBuilder builder; + TRY(builder.try_append("ClipboardGrabMessage { "sv)); + TRY(builder.try_appendff("types = {}", types())); + TRY(builder.try_append(" }"sv)); + return builder.to_string(); +} + } diff --git a/Userland/Services/SpiceAgent/Message.h b/Userland/Services/SpiceAgent/Message.h index 6799f9eefa9..dc0a0725ba7 100644 --- a/Userland/Services/SpiceAgent/Message.h +++ b/Userland/Services/SpiceAgent/Message.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include @@ -37,6 +38,17 @@ enum class Capability : u32 { ClipboardGrabSerial }; +// Used to describe the type of data which is present on the user's clipboard. +enum class ClipboardDataType : u32 { + None = 0, + Text, + PNG, + BMP, + TIFF, + JPG, + __End +}; + class Message { public: // The spice protocol headers contain a bit of documentation about these, but nothing major: @@ -98,4 +110,64 @@ private: Vector m_capabilities; }; +// Sent/received to tell the server/client that clipboard data is available. +class ClipboardGrabMessage : public Message { +public: + ClipboardGrabMessage(Vector const& types) + : Message(Type::ClipboardGrab) + , m_types(types) + { + } + + static ErrorOr read_from_stream(AK::Stream& stream); + + ErrorOr write_to_stream(AK::Stream& stream); + ErrorOr debug_description() override; + + Vector const& types() { return m_types; } + +private: + Vector m_types; +}; + +} + +namespace AK { +template<> +struct Formatter : Formatter { + ErrorOr format(FormatBuilder& builder, SpiceAgent::ClipboardDataType const& header) + { + auto string = "Unknown"sv; + switch (header) { + case SpiceAgent::ClipboardDataType::None: + string = "None"sv; + break; + + case SpiceAgent::ClipboardDataType::Text: + string = "Text"sv; + break; + + case SpiceAgent::ClipboardDataType::PNG: + string = "PNG"sv; + break; + + case SpiceAgent::ClipboardDataType::BMP: + string = "BMP"sv; + break; + + case SpiceAgent::ClipboardDataType::TIFF: + string = "TIFF"sv; + break; + + case SpiceAgent::ClipboardDataType::JPG: + string = "JPG"sv; + break; + + default: + break; + } + + return Formatter::format(builder, string); + } +}; } diff --git a/Userland/Services/SpiceAgent/SpiceAgent.cpp b/Userland/Services/SpiceAgent/SpiceAgent.cpp index 0ef134e7a80..5350ba8c1ed 100644 --- a/Userland/Services/SpiceAgent/SpiceAgent.cpp +++ b/Userland/Services/SpiceAgent/SpiceAgent.cpp @@ -64,6 +64,20 @@ ErrorOr SpiceAgent::on_message_received() break; } + case Message::Type::ClipboardGrab: { + auto message = TRY(ClipboardGrabMessage::read_from_stream(stream)); + if (message.types().is_empty()) + break; + + auto data_type = message.types().first(); + if (data_type == ClipboardDataType::None) + break; + + dbgln_if(SPICE_AGENT_DEBUG, "The spice server has notified us of new clipboard data of type: {}", data_type); + + break; + } + // We ignore certain messages to prevent it from clogging up the logs. case Message::Type::MonitorsConfig: dbgln_if(SPICE_AGENT_DEBUG, "Ignored message: {}", header);