Add the base for GUI handling

Still need to embed the opened window into the window provided by the
host.
This commit is contained in:
Robbert van der Helm
2020-03-17 01:50:50 +01:00
parent 44a953c2d2
commit e7e1b26455
6 changed files with 91 additions and 27 deletions
+11 -1
View File
@@ -208,7 +208,8 @@ void passthrough_event(boost::asio::local::stream_protocol::socket& socket,
},
[&](WantsChunkBuffer&) -> void* { return string_buffer.data(); },
[&](const WantsVstTimeInfo&) -> void* { return nullptr; },
[&](WantsString&) -> void* { return string_buffer.data(); }},
[&](WantsString&) -> void* { return string_buffer.data(); },
[&](WantsWindowHandle&) -> void* { return string_buffer.data(); }},
event.payload);
const intptr_t return_value = callback(plugin, event.opcode, event.index,
@@ -263,6 +264,15 @@ void passthrough_event(boost::asio::local::stream_protocol::socket& socket,
},
[&](WantsString&) -> EventResposnePayload {
return std::string(static_cast<char*>(data));
},
[&](WantsWindowHandle&) -> EventResposnePayload {
// This is a bit of a hack, but I couldn't think of a nicer
// way to do this since it's only needed for the
// `effEditOpen` event. We override the callback function
// to create a Win32 window, pass that to the plugin, and
// then write the corresponding X11 window handle to the
// data pointer.
return *reinterpret_cast<intptr_t*>(data);
}},
event.payload);
+6 -2
View File
@@ -175,7 +175,8 @@ void Logger::log_event(bool is_dispatch,
message << "<writable_buffer>";
},
[&](const WantsVstTimeInfo&) { message << "<nullptr>"; },
[&](const WantsString&) { message << "<writable_string>"; }},
[&](const WantsString&) { message << "<writable_string>"; },
[&](const WantsWindowHandle&) { message << "<nullptr>"; }},
payload);
message << ")";
@@ -209,7 +210,10 @@ void Logger::log_event_response(bool is_dispatch,
}
},
[&](const AEffect&) { message << ", <AEffect_object>"; },
[&](const VstTimeInfo&) { message << ", <time_info>"; }},
[&](const VstTimeInfo&) { message << ", <time_info>"; },
[&](const intptr_t& window_handle) {
message << ", window #" << window_handle;
}},
payload);
log(message.str());
+28 -20
View File
@@ -164,6 +164,12 @@ struct WantsVstTimeInfo {};
*/
struct WantsString {};
/**
* The event handler (the Wine VST host) should create a Winn32 window, pass
* that to the plugin, and return an X11 window handle.
*/
struct WantsWindowHandle {};
/**
* VST events are passed a void pointer that can contain a variety of different
* data types depending on the event's opcode. This is typically either:
@@ -197,27 +203,27 @@ using EventPayload = std::variant<std::nullptr_t,
DynamicVstEvents,
WantsChunkBuffer,
WantsVstTimeInfo,
WantsString>;
WantsString,
WantsWindowHandle>;
template <typename S>
void serialize(S& s, EventPayload& payload) {
s.ext(payload, bitsery::ext::StdVariant{
[](S&, std::nullptr_t&) {},
[](S& s, std::string& string) {
// `binary_buffer_size` and not `max_string_length`
// because we also use this to send back large chunk
// data
s.text1b(string, binary_buffer_size);
},
[](S& s, AEffect& effect) { s.object(effect); },
[](S& s, DynamicVstEvents& events) {
s.container(events.events, max_midi_events,
[](S& s, VstEvent& event) {
s.container1b(event.dump);
});
},
[](S&, WantsChunkBuffer&) {},
[](S&, WantsVstTimeInfo&) {}, [](S&, WantsString&) {}});
s.ext(payload,
bitsery::ext::StdVariant{
[](S&, std::nullptr_t&) {},
[](S& s, std::string& string) {
// `binary_buffer_size` and not `max_string_length` because we
// also use this to send back large chunk data
s.text1b(string, binary_buffer_size);
},
[](S& s, AEffect& effect) { s.object(effect); },
[](S& s, DynamicVstEvents& events) {
s.container(
events.events, max_midi_events,
[](S& s, VstEvent& event) { s.container1b(event.dump); });
},
[](S&, WantsChunkBuffer&) {}, [](S&, WantsVstTimeInfo&) {},
[](S&, WantsString&) {}, [](S&, WantsWindowHandle&) {}});
}
/**
@@ -270,9 +276,10 @@ struct Event {
* instenad.
* - A specific struct in response to an event such as `audioMasterGetTime` or
* `audioMasterIOChanged`.
* - An X11 window pointer for the editor window.
*/
using EventResposnePayload =
std::variant<std::monostate, std::string, AEffect, VstTimeInfo>;
std::variant<std::monostate, std::string, AEffect, VstTimeInfo, intptr_t>;
template <typename S>
void serialize(S& s, EventResposnePayload& payload) {
@@ -286,7 +293,8 @@ void serialize(S& s, EventResposnePayload& payload) {
s.text1b(string, binary_buffer_size);
},
[](S& s, AEffect& effect) { s.object(effect); },
[](S& s, VstTimeInfo& time_info) { s.object(time_info); }});
[](S& s, VstTimeInfo& time_info) { s.object(time_info); },
[](S& s, intptr_t& v) { s.value8b(v); }});
}
/**
+21 -2
View File
@@ -183,7 +183,6 @@ class DispatchDataConverter : DefaultDataConverter {
switch (opcode) {
// TODO: Add GUI support. These events are just disabled for now to
// ensure everything else works first.
case effEditOpen:
case effEditTop:
case effEditIdle:
case effEditClose:
@@ -195,6 +194,9 @@ class DispatchDataConverter : DefaultDataConverter {
return std::nullopt;
break;
case effEditOpen:
return WantsWindowHandle();
break;
case effGetChunk:
return WantsChunkBuffer();
break;
@@ -214,6 +216,10 @@ class DispatchDataConverter : DefaultDataConverter {
void write(const int opcode, void* data, const EventResult& response) {
switch (opcode) {
case effEditOpen:
// TODO: Write the returned window handle somewhere
DefaultDataConverter::write(opcode, data, response);
break;
case effGetChunk:
// Write the chunk data to some publically accessible place in
// `HostBridge` and write a pointer to that struct to the data
@@ -253,8 +259,21 @@ intptr_t HostBridge::dispatch(AEffect* /*plugin*/,
DispatchDataConverter converter(chunk_data);
// Some events need some extra handling
// TODO: Handle other things such as GUI itneraction
// TODO: Handle GUI closing?
switch (opcode) {
case effEditOpen:
// TODO: Should work as follows:
// 1. Create a window in the Wine host using the Windows APIs
// 2. Return the X11 window handle
// 4. Use XEmbed to embmed the Wine window inside the parent
// window stored in the data void pointer
// 5. Return a handle to the X11 window
send_event(host_vst_dispatch, dispatch_semaphore, converter,
std::pair<Logger&, bool>(logger, true), opcode, index,
value, data, option);
return 0;
break;
case effClose:
// TODO: Gracefully close the editor?
// TODO: Check whether the sockets and the endpoint are closed
+22 -2
View File
@@ -123,8 +123,28 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
// lockstep anyway
dispatch_handler = std::thread([&]() {
while (true) {
passthrough_event(host_vst_dispatch, std::nullopt, plugin,
plugin->dispatcher);
passthrough_event(
host_vst_dispatch, std::nullopt, plugin,
[&](AEffect* plugin, int opcode, int index, intptr_t value,
void* data, float option) -> intptr_t {
// TODO: editEffClose
// We have to intercept GUI open calls since we can't use
// the X11 window handle passed by the host
if (opcode == effEditOpen) {
const auto handle = editor.open();
const intptr_t return_value = plugin->dispatcher(
plugin, opcode, index, value, handle, option);
if (return_value == 0) {
return 0;
}
// TODO: Return X11 handle
return return_value;
}
return plugin->dispatcher(plugin, opcode, index, value,
data, option);
});
}
});
+3
View File
@@ -31,6 +31,7 @@
#include <thread>
#include "../common/logging.h"
#include "win32-editor.h"
/**
* This handles the communication between the Linux native VST plugin and the
@@ -128,4 +129,6 @@ class PluginBridge {
* `processReplacing` calls.
*/
std::vector<uint8_t> process_buffer;
Win32Editor editor;
};