diff --git a/src/common/serialization/clap.h b/src/common/serialization/clap.h index c25c4492..85c9306c 100644 --- a/src/common/serialization/clap.h +++ b/src/common/serialization/clap.h @@ -23,6 +23,7 @@ #include "../bitsery/ext/message-reference.h" #include "../utils.h" #include "clap/ext/audio-ports.h" +#include "clap/ext/gui.h" #include "clap/ext/latency.h" #include "clap/ext/note-ports.h" #include "clap/ext/params.h" diff --git a/src/common/serialization/clap/ext/gui.h b/src/common/serialization/clap/ext/gui.h new file mode 100644 index 00000000..658d6427 --- /dev/null +++ b/src/common/serialization/clap/ext/gui.h @@ -0,0 +1,412 @@ +// yabridge: a Wine plugin bridge +// Copyright (C) 2020-2022 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more deguis. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +#include + +#include "../../../bitsery/ext/in-place-optional.h" +#include "../../common.h" + +// Serialization messages for `clap/ext/gui.h` + +// Like the VST3 GUI handling, we'll translate the "X11" API type to "HWND" on +// the Wine side. + +// TODO: We only support the embedded parts of the API on both sides right now. +// Floating modes where the plugin window is still embedded and the +// toplevel Wine window is floating would be possible. Having the plugin's +// own window be floating all by itself is also possible, but then +// `set_transient()` wouldn't be possible which would make it awkward to +// use. + +namespace clap { +namespace ext { +namespace gui { + +/** + * The API types we can embed windows for. Technically we could also allow the + * host to send a HWND directly if it also did some Winelib trickery, but + * realistically that won't ever happen. + */ +enum class ApiType : uint32_t { X11 }; + +namespace plugin { + +/** + * Message struct for `clap_plugin_gui::is_api_supported()`. + */ +struct IsApiSupported { + using Response = PrimitiveResponse; + + native_size_t instance_id; + /** + * This will always be X11, we'll currently ignore anything else. X11 gets + * translated to HWND before passing it to the plugin. + */ + ApiType api; + /** + * This will always be false, we'll currently ignore anything else. + */ + bool is_floating; + + template + void serialize(S& s) { + s.value8b(instance_id); + s.value4b(api); + s.value1b(is_floating); + } +}; + +// NOTE: We currently don't bridge `clap_plugin_gui::get_preferred_api()` since +// it doesn't make much sense. We'll always return X11 floating from +// there. + +/** + * Message struct for `clap_plugin_gui::create()`. + */ +struct Create { + using Response = PrimitiveResponse; + + native_size_t instance_id; + /** + * This will always be X11, we'll currently ignore anything else. X11 gets + * translated to HWND before passing it to the plugin. + */ + ApiType api; + /** + * This will always be false, we'll currently ignore anything else. + */ + bool is_floating; + + template + void serialize(S& s) { + s.value8b(instance_id); + s.value4b(api); + s.value1b(is_floating); + } +}; + +/** + * Message struct for `clap_plugin_gui::destroy()`. + */ +struct Destroy { + using Response = Ack; + + native_size_t instance_id; + + template + void serialize(S& s) { + s.value8b(instance_id); + } +}; + +/** + * Message struct for `clap_plugin_gui::set_scale()`. + */ +struct SetScale { + using Response = PrimitiveResponse; + + native_size_t instance_id; + double scale; + + template + void serialize(S& s) { + s.value8b(instance_id); + s.value8b(scale); + } +}; + +/** + * The response to the `clap::ext::params::GetSize` message defined below. + */ +struct GetSizeResponse { + bool result; + + uint32_t width; + uint32_t height; + + template + void serialize(S& s) { + s.value1b(result); + s.value4b(width); + s.value4b(height); + } +}; + +/** + * Message struct for `clap_plugin_gui::get_size()`. + */ +struct GetSize { + using Response = GetSizeResponse; + + native_size_t instance_id; + + template + void serialize(S& s) { + s.value8b(instance_id); + } +}; + +/** + * Message struct for `clap_plugin_gui::can_resize()`. + */ +struct CanResize { + using Response = PrimitiveResponse; + + native_size_t instance_id; + + template + void serialize(S& s) { + s.value8b(instance_id); + } +}; + +/** + * The response to the `clap::ext::params::GetResizeHints` message defined + * below. + */ +struct GetResizeHintsResponse { + // This doesn't require a special wrapper since the struct only contains + // primitive values. Its serialization function is defined at the bottom of + // this header. + std::optional result; + + template + void serialize(S& s) { + s.ext(result, bitsery::ext::InPlaceOptional(), + [](S& s, auto& v) { s.object(v); }); + } +}; + +/** + * Message struct for `clap_plugin_gui::get_resize_hints()`. + */ +struct GetResizeHints { + using Response = GetResizeHintsResponse; + + native_size_t instance_id; + + template + void serialize(S& s) { + s.value8b(instance_id); + } +}; + +/** + * The response to the `clap::ext::params::AdjustSize` message defined below. + */ +struct AdjustSizeResponse { + bool result; + + uint32_t updated_width; + uint32_t updated_height; + + template + void serialize(S& s) { + s.value1b(result); + s.value4b(updated_width); + s.value4b(updated_height); + } +}; + +/** + * Message struct for `clap_plugin_gui::adjust_size()`. + */ +struct AdjustSize { + using Response = AdjustSizeResponse; + + native_size_t instance_id; + + uint32_t width; + uint32_t height; + + template + void serialize(S& s) { + s.value8b(instance_id); + s.value4b(width); + s.value4b(height); + } +}; + +/** + * Message struct for `clap_plugin_gui::set_size()`. + */ +struct SetSize { + using Response = PrimitiveResponse; + + native_size_t instance_id; + + uint32_t width; + uint32_t height; + + template + void serialize(S& s) { + s.value8b(instance_id); + s.value4b(width); + s.value4b(height); + } +}; + +/** + * Message struct for `clap_plugin_gui::set_parent()`. + */ +struct SetParent { + using Response = PrimitiveResponse; + + native_size_t instance_id; + + // We only support X11 right now, so we can simplify this a little + clap_xwnd x11_window; + + template + void serialize(S& s) { + s.value8b(instance_id); + s.value8b(x11_window); + } +}; + +// NOTE: There are no structs for `clap_plugin_gui::set_transient()` or +// `clap_plugin_gui::suggest_title()` since Wine-only floating windows +// wouldn't be able to set the transient window (which would be an X11 +// window). + +/** + * Message struct for `clap_plugin_gui::show()`. + */ +struct Show { + using Response = PrimitiveResponse; + + native_size_t instance_id; + + template + void serialize(S& s) { + s.value8b(instance_id); + } +}; + +/** + * Message struct for `clap_plugin_gui::hide()`. + */ +struct Hide { + using Response = PrimitiveResponse; + + native_size_t instance_id; + + template + void serialize(S& s) { + s.value8b(instance_id); + } +}; + +} // namespace plugin + +namespace host { + +/** + * Message struct for `clap_host_gui::resize_hints_changed()`. + */ +struct ResizeHintsChanged { + using Response = Ack; + + native_size_t owner_instance_id; + + template + void serialize(S& s) { + s.value8b(owner_instance_id); + } +}; + +/** + * Message struct for `clap_host_gui::request_resize()`. + */ +struct RequestResize { + using Response = PrimitiveResponse; + + native_size_t owner_instance_id; + + uint32_t width; + uint32_t height; + + template + void serialize(S& s) { + s.value8b(owner_instance_id); + s.value4b(width); + s.value4b(height); + } +}; + +/** + * Message struct for `clap_host_gui::request_show()`. + */ +struct RequestShow { + using Response = PrimitiveResponse; + + native_size_t owner_instance_id; + + template + void serialize(S& s) { + s.value8b(owner_instance_id); + } +}; + +/** + * Message struct for `clap_host_gui::request_hide()`. + */ +struct RequestHide { + using Response = PrimitiveResponse; + + native_size_t owner_instance_id; + + template + void serialize(S& s) { + s.value8b(owner_instance_id); + } +}; + +/** + * Message struct for `clap_host_gui::closed()`. + */ +struct Closed { + using Response = Ack; + + native_size_t owner_instance_id; + + bool was_destroyed; + + template + void serialize(S& s) { + s.value8b(owner_instance_id); + s.value1b(was_destroyed); + } +}; + +} // namespace host + +} // namespace gui +} // namespace ext +} // namespace clap + +template +void serialize(S& s, clap_gui_resize_hints_t& hints) { + s.value1b(hints.can_resize_horizontally); + s.value1b(hints.can_resize_vertically); + s.value1b(hints.preserve_aspect_ratio); + s.value4b(hints.aspect_ratio_width); + s.value4b(hints.aspect_ratio_height); +}