mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +02:00
Remove Win32 effEditIdle() timer
Now Editor is completely decoupled from VST2.
This commit is contained in:
@@ -42,10 +42,12 @@ std::mutex current_bridge_instance_mutex;
|
|||||||
/**
|
/**
|
||||||
* Opcodes that should always be handled on the main thread because they may
|
* Opcodes that should always be handled on the main thread because they may
|
||||||
* involve GUI operations.
|
* involve GUI operations.
|
||||||
|
*
|
||||||
|
* XXX: We removed effEditIdle from here and everything still seems to work
|
||||||
|
* fine. Verify that this didn't break any plugins.
|
||||||
*/
|
*/
|
||||||
const std::set<int> unsafe_opcodes{effOpen, effClose, effEditGetRect,
|
const std::set<int> unsafe_opcodes{effOpen, effClose, effEditGetRect,
|
||||||
effEditOpen, effEditClose, effEditIdle,
|
effEditOpen, effEditClose, effEditTop};
|
||||||
effEditTop};
|
|
||||||
|
|
||||||
intptr_t VST_CALL_CONV
|
intptr_t VST_CALL_CONV
|
||||||
host_callback_proxy(AEffect*, int, int, intptr_t, void*, float);
|
host_callback_proxy(AEffect*, int, int, intptr_t, void*, float);
|
||||||
@@ -391,7 +393,7 @@ intptr_t Vst2Bridge::dispatch_wrapper(AEffect* plugin,
|
|||||||
const std::string window_class =
|
const std::string window_class =
|
||||||
"yabridge plugin " + sockets.base_dir.string();
|
"yabridge plugin " + sockets.base_dir.string();
|
||||||
Editor& editor_instance =
|
Editor& editor_instance =
|
||||||
editor.emplace(config, window_class, x11_handle, plugin);
|
editor.emplace(config, window_class, x11_handle);
|
||||||
|
|
||||||
return plugin->dispatcher(plugin, opcode, index, value,
|
return plugin->dispatcher(plugin, opcode, index, value,
|
||||||
editor_instance.get_win32_handle(),
|
editor_instance.get_win32_handle(),
|
||||||
|
|||||||
@@ -18,9 +18,6 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
// The Win32 API requires you to hardcode identifiers for tiemrs
|
|
||||||
constexpr size_t idle_timer_id = 1337;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The most significant bit in an event's response type is used to indicate
|
* The most significant bit in an event's response type is used to indicate
|
||||||
* whether the event source.
|
* whether the event source.
|
||||||
@@ -84,8 +81,7 @@ WindowClass::~WindowClass() {
|
|||||||
|
|
||||||
Editor::Editor(const Configuration& config,
|
Editor::Editor(const Configuration& config,
|
||||||
const std::string& window_class_name,
|
const std::string& window_class_name,
|
||||||
const size_t parent_window_handle,
|
const size_t parent_window_handle)
|
||||||
AEffect* effect)
|
|
||||||
: x11_connection(xcb_connect(nullptr, nullptr), xcb_disconnect),
|
: x11_connection(xcb_connect(nullptr, nullptr), xcb_disconnect),
|
||||||
client_area(get_maximum_screen_dimensions(*x11_connection)),
|
client_area(get_maximum_screen_dimensions(*x11_connection)),
|
||||||
window_class(window_class_name),
|
window_class(window_class_name),
|
||||||
@@ -110,12 +106,10 @@ Editor::Editor(const Configuration& config,
|
|||||||
// If `config.editor_double_embed` is set, then we'll also create a child
|
// If `config.editor_double_embed` is set, then we'll also create a child
|
||||||
// window in `win32_child_handle`. If we do this before calling
|
// window in `win32_child_handle`. If we do this before calling
|
||||||
// `ShowWindow()` on `win32_handle` we'll run into X11 errors.
|
// `ShowWindow()` on `win32_handle` we'll run into X11 errors.
|
||||||
idle_timer(win32_handle.get(), idle_timer_id, 100),
|
win32_child_handle(std::nullopt),
|
||||||
parent_window(parent_window_handle),
|
parent_window(parent_window_handle),
|
||||||
wine_window(get_x11_handle(win32_handle.get())),
|
wine_window(get_x11_handle(win32_handle.get())),
|
||||||
topmost_window(find_topmost_window(*x11_connection, parent_window)),
|
topmost_window(find_topmost_window(*x11_connection, parent_window)) {
|
||||||
// Needed to send update messages on a timer
|
|
||||||
plugin(effect) {
|
|
||||||
xcb_generic_error_t* error;
|
xcb_generic_error_t* error;
|
||||||
|
|
||||||
// Used for input focus grabbing to only grab focus when the window is
|
// Used for input focus grabbing to only grab focus when the window is
|
||||||
@@ -225,10 +219,6 @@ HWND Editor::get_win32_handle() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::send_idle_event() {
|
|
||||||
plugin->dispatcher(plugin, effEditIdle, 0, 0, nullptr, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Editor::handle_win32_events() const {
|
void Editor::handle_win32_events() const {
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
|
||||||
@@ -236,21 +226,11 @@ void Editor::handle_win32_events() const {
|
|||||||
// with child GUI components. So far limiting this to `max_win32_messages`
|
// with child GUI components. So far limiting this to `max_win32_messages`
|
||||||
// messages has only been needed for Waves plugins as they otherwise cause
|
// messages has only been needed for Waves plugins as they otherwise cause
|
||||||
// an infinite message loop.
|
// an infinite message loop.
|
||||||
|
// TODO: If the timer is no longer needed, then we can drop this entire
|
||||||
|
// function
|
||||||
for (int i = 0;
|
for (int i = 0;
|
||||||
i < max_win32_messages && PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
|
i < max_win32_messages && PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
|
||||||
i++) {
|
i++) {
|
||||||
// This timer would periodically send `effEditIdle` events so the editor
|
|
||||||
// remains responsive even during blocking GUI operations such as open
|
|
||||||
// dropdowns or message boxes. This is only needed when the GUI is
|
|
||||||
// actually blocked and it will be dispatched by the messaging loop of
|
|
||||||
// the blocking GUI component. Since we're not touching the
|
|
||||||
// `effEditIdle` event sent by the host we can always filter this timer
|
|
||||||
// event out in this event loop.
|
|
||||||
if (msg.message == WM_TIMER && msg.wParam == idle_timer_id &&
|
|
||||||
msg.hwnd == win32_handle.get()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
@@ -470,20 +450,6 @@ LRESULT CALLBACK window_proc(HWND handle,
|
|||||||
SetWindowLongPtr(handle, GWLP_USERDATA,
|
SetWindowLongPtr(handle, GWLP_USERDATA,
|
||||||
reinterpret_cast<size_t>(editor));
|
reinterpret_cast<size_t>(editor));
|
||||||
} break;
|
} break;
|
||||||
case WM_TIMER: {
|
|
||||||
auto editor = reinterpret_cast<Editor*>(
|
|
||||||
GetWindowLongPtr(handle, GWLP_USERDATA));
|
|
||||||
if (!editor || wParam != idle_timer_id) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll send idle messages on a timer. This way the plugin will get
|
|
||||||
// keep periodically updating its editor either when the host sends
|
|
||||||
// `effEditIdle` themself, or periodically when the GUI is being
|
|
||||||
// blocked by a dropdown or a message box.
|
|
||||||
editor->send_idle_event();
|
|
||||||
return 0;
|
|
||||||
} break;
|
|
||||||
// In case the WM does not support the EWMH active window property,
|
// In case the WM does not support the EWMH active window property,
|
||||||
// we'll fall back to grabbing focus when the user clicks on the window
|
// we'll fall back to grabbing focus when the user clicks on the window
|
||||||
// by listening to the generated `WM_PARENTNOTIFY` messages. Otherwise
|
// by listening to the generated `WM_PARENTNOTIFY` messages. Otherwise
|
||||||
|
|||||||
+9
-34
@@ -16,22 +16,21 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Use the native version of xcb
|
#include <memory>
|
||||||
#pragma push_macro("_WIN32")
|
#include <optional>
|
||||||
#undef _WIN32
|
#include <string>
|
||||||
#include <xcb/xcb.h>
|
|
||||||
#pragma pop_macro("_WIN32")
|
|
||||||
|
|
||||||
#ifndef NOMINMAX
|
#ifndef NOMINMAX
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#define WINE_NOWINSOCK
|
#define WINE_NOWINSOCK
|
||||||
#endif
|
#endif
|
||||||
#include <vestige/aeffectx.h>
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <memory>
|
// Use the native version of xcb
|
||||||
#include <optional>
|
#pragma push_macro("_WIN32")
|
||||||
#include <string>
|
#undef _WIN32
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
#pragma pop_macro("_WIN32")
|
||||||
|
|
||||||
#include "../common/configuration.h"
|
#include "../common/configuration.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@@ -101,15 +100,12 @@ class Editor {
|
|||||||
* windows.
|
* windows.
|
||||||
* @param parent_window_handle The X11 window handle passed by the VST host
|
* @param parent_window_handle The X11 window handle passed by the VST host
|
||||||
* for the editor to embed itself into.
|
* for the editor to embed itself into.
|
||||||
* @param effect The plugin this window is being created for. Used to send
|
|
||||||
* `effEditIdle` messages on a timer.
|
|
||||||
*
|
*
|
||||||
* @see win32_handle
|
* @see win32_handle
|
||||||
*/
|
*/
|
||||||
Editor(const Configuration& config,
|
Editor(const Configuration& config,
|
||||||
const std::string& window_class_name,
|
const std::string& window_class_name,
|
||||||
const size_t parent_window_handle,
|
const size_t parent_window_handle);
|
||||||
AEffect* effect);
|
|
||||||
|
|
||||||
~Editor();
|
~Editor();
|
||||||
|
|
||||||
@@ -131,13 +127,6 @@ class Editor {
|
|||||||
*/
|
*/
|
||||||
bool supports_ewmh_active_window() const;
|
bool supports_ewmh_active_window() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a single `effEditIdle` event to the plugin to allow it to update its
|
|
||||||
* GUI state. This is called periodically from a timer while the GUI is
|
|
||||||
* being blocked, and also called explicitly by the host on a timer.
|
|
||||||
*/
|
|
||||||
void send_idle_event();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pump messages from the editor loop loop until all events are process.
|
* Pump messages from the editor loop loop until all events are process.
|
||||||
* Must be run from the same thread the GUI was created in because of Win32
|
* Must be run from the same thread the GUI was created in because of Win32
|
||||||
@@ -225,15 +214,6 @@ class Editor {
|
|||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
/**
|
|
||||||
* The Win32 API will block the `DispatchMessage` call when opening e.g. a
|
|
||||||
* dropdown, but it will still allow timers to be run so the GUI can still
|
|
||||||
* update in the background. Because of this we send `effEditIdle` to the
|
|
||||||
* plugin on a timer. The refresh rate is purposely fairly low since the
|
|
||||||
* host will call `effEditIdle()` explicitely when the plugin is not busy.
|
|
||||||
*/
|
|
||||||
Win32Timer idle_timer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The window handle of the editor window created by the DAW.
|
* The window handle of the editor window created by the DAW.
|
||||||
*/
|
*/
|
||||||
@@ -252,11 +232,6 @@ class Editor {
|
|||||||
*/
|
*/
|
||||||
const xcb_window_t topmost_window;
|
const xcb_window_t topmost_window;
|
||||||
|
|
||||||
/**
|
|
||||||
*Needed to handle idle updates through a timer
|
|
||||||
*/
|
|
||||||
AEffect* plugin;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The atom corresponding to `_NET_ACTIVE_WINDOW`.
|
* The atom corresponding to `_NET_ACTIVE_WINDOW`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user