1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 01:17:35 +00:00

SpiceAgent: Add support for copying images to the clipboard

This commit is contained in:
Caoimhe 2023-05-13 15:24:53 +01:00 committed by Andreas Kling
parent 50a8db3922
commit 9f92e52464
4 changed files with 63 additions and 11 deletions

View file

@ -11,6 +11,38 @@
namespace SpiceAgent { namespace SpiceAgent {
ErrorOr<String> clipboard_data_type_to_mime_type(ClipboardDataType data_type)
{
switch (data_type) {
case ClipboardDataType::Text:
return "text/plain"_string;
case ClipboardDataType::PNG:
return "image/png"_string;
case ClipboardDataType::BMP:
return "image/bitmap"_string;
case ClipboardDataType::JPG:
return "image/jpeg"_string;
case ClipboardDataType::TIFF:
return "image/tiff"_string;
default:
return Error::from_string_literal("Unable to determine mime type!");
}
}
ErrorOr<ClipboardDataType> clipboard_data_type_from_raw_value(u32 value)
{
if (value >= to_underlying(ClipboardDataType::__End)) {
return Error::from_string_literal("Unsupported clipboard type");
}
return static_cast<ClipboardDataType>(value);
}
ErrorOr<AnnounceCapabilitiesMessage> AnnounceCapabilitiesMessage::read_from_stream(AK::Stream& stream) ErrorOr<AnnounceCapabilitiesMessage> AnnounceCapabilitiesMessage::read_from_stream(AK::Stream& stream)
{ {
// If this message is a capabilities request, we don't have to parse anything else. // If this message is a capabilities request, we don't have to parse anything else.
@ -57,11 +89,7 @@ ErrorOr<ClipboardGrabMessage> ClipboardGrabMessage::read_from_stream(AK::Stream&
auto types = Vector<ClipboardDataType>(); auto types = Vector<ClipboardDataType>();
while (!stream.is_eof()) { while (!stream.is_eof()) {
auto value = TRY(stream.read_value<u32>()); auto value = TRY(stream.read_value<u32>());
if (value >= to_underlying(ClipboardDataType::__End)) { types.append(TRY(clipboard_data_type_from_raw_value(value)));
return Error::from_string_literal("Unsupported clipboard type");
}
types.append(static_cast<ClipboardDataType>(value));
} }
return ClipboardGrabMessage(types); return ClipboardGrabMessage(types);
@ -88,11 +116,7 @@ ErrorOr<String> ClipboardGrabMessage::debug_description()
ErrorOr<ClipboardRequestMessage> ClipboardRequestMessage::read_from_stream(AK::Stream& stream) ErrorOr<ClipboardRequestMessage> ClipboardRequestMessage::read_from_stream(AK::Stream& stream)
{ {
auto value = TRY(stream.read_value<u32>()); auto value = TRY(stream.read_value<u32>());
if (value >= to_underlying(ClipboardDataType::__End)) { auto type = TRY(clipboard_data_type_from_raw_value(value));
return Error::from_string_literal("Unsupported clipboard type");
}
auto type = static_cast<ClipboardDataType>(value);
return ClipboardRequestMessage(type); return ClipboardRequestMessage(type);
} }

View file

@ -9,6 +9,7 @@
#include <AK/ByteBuffer.h> #include <AK/ByteBuffer.h>
#include <AK/Format.h> #include <AK/Format.h>
#include <AK/Forward.h> #include <AK/Forward.h>
#include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
namespace SpiceAgent { namespace SpiceAgent {
@ -50,6 +51,9 @@ enum class ClipboardDataType : u32 {
__End __End
}; };
ErrorOr<String> clipboard_data_type_to_mime_type(ClipboardDataType type);
ErrorOr<ClipboardDataType> clipboard_data_type_from_raw_value(u32 value);
class Message { class Message {
public: public:
// The spice protocol headers contain a bit of documentation about these, but nothing major: // The spice protocol headers contain a bit of documentation about these, but nothing major:

View file

@ -8,6 +8,7 @@
#include "SpiceAgent.h" #include "SpiceAgent.h"
#include <AK/Debug.h> #include <AK/Debug.h>
#include <LibGUI/Clipboard.h> #include <LibGUI/Clipboard.h>
#include <LibGfx/ImageFormats/ImageDecoder.h>
namespace SpiceAgent { namespace SpiceAgent {
@ -111,11 +112,33 @@ ErrorOr<void> SpiceAgent::did_receive_clipboard_message(ClipboardMessage& messag
case ClipboardDataType::Text: { case ClipboardDataType::Text: {
// The default mime_type for set_data is `text/plain`. // The default mime_type for set_data is `text/plain`.
GUI::Clipboard::the().set_data(message.contents()); GUI::Clipboard::the().set_data(message.contents());
return {}; break;
} }
// For the image formats, let's try to find a decoder from LibGfx.
case ClipboardDataType::PNG:
case ClipboardDataType::BMP:
case ClipboardDataType::JPG:
case ClipboardDataType::TIFF: {
auto mime_type = TRY(clipboard_data_type_to_mime_type(message.data_type()));
// FIXME: It should be trivial to make `try_create_for_raw_bytes` take a `StringView` instead of a direct `DeprecatedString`.
auto decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(message.contents(), mime_type.to_deprecated_string());
if (!decoder || (decoder->frame_count() == 0)) {
return Error::from_string_literal("Failed to find a suitable decoder for a pasted image!");
}
auto frame = TRY(decoder->frame(0));
GUI::Clipboard::the().set_bitmap(*frame.image);
break;
}
default: default:
return Error::from_string_literal("Unsupported clipboard data type!"); return Error::from_string_literal("Unsupported clipboard data type!");
} }
return {};
} }
ErrorOr<ByteBuffer> SpiceAgent::read_message_buffer() ErrorOr<ByteBuffer> SpiceAgent::read_message_buffer()

View file

@ -11,6 +11,7 @@
#include "Message.h" #include "Message.h"
#include "MessageHeader.h" #include "MessageHeader.h"
#include <AK/MemoryStream.h> #include <AK/MemoryStream.h>
#include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCore/File.h> #include <LibCore/File.h>
#include <LibCore/Notifier.h> #include <LibCore/Notifier.h>