From ca883da5b25389c366df1e92d865242fc52ffc13 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 19 Jul 2021 12:59:16 +0200 Subject: [PATCH 1/6] Add tracing for the various X11 events --- src/wine-host/editor.cpp | 80 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp index dc898eb9..287d0e36 100644 --- a/src/wine-host/editor.cpp +++ b/src/wine-host/editor.cpp @@ -334,6 +334,10 @@ Editor::Editor(MainContext& main_context, XCB_CW_EVENT_MASK, &parent_event_mask); xcb_flush(x11_connection.get()); + std::cerr << "DEBUG: host_window: " << host_window << std::endl; + std::cerr << "DEBUG: parent_window: " << parent_window << std::endl; + std::cerr << "DEBUG: wine_window: " << wine_window << std::endl; + if (use_xembed) { // This call alone doesn't do anything. We need to call this function a // second time on visibility change because Wine's XEmbed implementation @@ -345,8 +349,18 @@ Editor::Editor(MainContext& main_context, // of using the XEmbed protocol, we'll register a few events and manage // the child window ourselves. This is a hack to work around the issue's // described in `Editor`'s docstring'. - xcb_reparent_window(x11_connection.get(), wine_window, parent_window, 0, - 0); + xcb_void_cookie_t reparent_cookie = xcb_reparent_window_checked( + x11_connection.get(), wine_window, parent_window, 0, 0); + if (std::unique_ptr error( + xcb_request_check(x11_connection.get(), reparent_cookie)); + error) { + std::cerr << "DEBUG: Reparent 1 failed:" << std::endl; + std::cerr << "Error code: " << error->error_code << std::endl; + std::cerr << "Major code: " << error->major_code << std::endl; + std::cerr << "Minor code: " << error->minor_code << std::endl; + } else { + std::cerr << "DEBUG: Reparent 1 succeeded" << std::endl; + } xcb_flush(x11_connection.get()); // If we're using the double embedding option, then the child window @@ -373,8 +387,18 @@ Editor::Editor(MainContext& main_context, // trying! // // https://github.com/robbert-vdh/yabridge/issues/40 - xcb_reparent_window(x11_connection.get(), wine_window, parent_window, 0, - 0); + reparent_cookie = xcb_reparent_window_checked( + x11_connection.get(), wine_window, parent_window, 0, 0); + if (std::unique_ptr error( + xcb_request_check(x11_connection.get(), reparent_cookie)); + error) { + std::cerr << "DEBUG: Reparent 2 failed:" << std::endl; + std::cerr << "Error code: " << error->error_code << std::endl; + std::cerr << "Major code: " << error->major_code << std::endl; + std::cerr << "Minor code: " << error->minor_code << std::endl; + } else { + std::cerr << "DEBUG: Reparent 2 succeeded" << std::endl; + } xcb_flush(x11_connection.get()); } } @@ -390,6 +414,10 @@ void Editor::handle_x11_events() noexcept { generic_event != nullptr) { const uint8_t event_type = generic_event->response_type & xcb_event_type_mask; + + std::cerr << "DEBUG: X11 event " << static_cast(event_type) + << std::endl; + switch (event_type) { // NOTE: When reopening a closed editor window in REAPER, REAPER // will initialize the editor first, and only then will it @@ -400,6 +428,12 @@ void Editor::handle_x11_events() noexcept { // check if the host's window has changed whenever the // parent window gets reparented. case XCB_REPARENT_NOTIFY: { + std::cerr << "DEBUG: ReparentNotify for window " + << reinterpret_cast( + generic_event.get()) + ->window + << std::endl; + redetect_host_window(); } break; // We're listening for `ConfigureNotify` events on the host's @@ -411,6 +445,13 @@ void Editor::handle_x11_events() noexcept { // check is sometimes necessary for using multiple editor // windows within a single plugin group. case XCB_CONFIGURE_NOTIFY: { + std::cerr + << "DEBUG: ConfigureNotify for window " + << reinterpret_cast( + generic_event.get()) + ->window + << std::endl; + if (!use_xembed) { fix_local_coordinates(); } @@ -419,6 +460,13 @@ void Editor::handle_x11_events() noexcept { // since most hosts will only show the window after the plugin // has embedded itself into it. case XCB_VISIBILITY_NOTIFY: { + std::cerr + << "DEBUG: VisibilityNotify for window " + << reinterpret_cast( + generic_event.get()) + ->window + << std::endl; + if (use_xembed) { do_xembed(); } @@ -437,6 +485,21 @@ void Editor::handle_x11_events() noexcept { fix_local_coordinates(); } + if (event_type == XCB_ENTER_NOTIFY) { + std::cerr + << "DEBUG: EnterNotify for window " + << reinterpret_cast( + generic_event.get()) + ->event + << std::endl; + } else { + std::cerr << "DEBUG: FocusIn for window " + << reinterpret_cast( + generic_event.get()) + ->event + << std::endl; + } + // In case the WM somehow does not support // `_NET_ACTIVE_WINDOW`, a more naive focus grabbing method // implemented in the `WM_PARENTNOTIFY` handler will be @@ -458,6 +521,9 @@ void Editor::handle_x11_events() noexcept { reinterpret_cast( generic_event.get()); + std::cerr << "DEBUG: LeaveNotify for window " + << event->event << std::endl; + // This extra check for the `NonlinearVirtual` detail is // important (see // https://www.x.org/releases/X11R7.5/doc/x11proto/proto.html @@ -474,6 +540,10 @@ void Editor::handle_x11_events() noexcept { set_input_focus(false); } } break; + default: { + std::cerr << "DEBUG: Unhandled X11 event " + << static_cast(event_type) << std::endl; + } } } } catch (const std::runtime_error& error) { @@ -630,6 +700,8 @@ void Editor::redetect_host_window() noexcept { return; } + std::cerr << "DEBUG: new host_window: " << new_host_window << std::endl; + // We need to readjust the event masks for the new host window, keeping the // (very probable) possibility in mind that the old host window is the same // as the parent window or that the parent window now is the host window. From 906ead26fd5104cdb47df8ec99cb505537ab8762 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 19 Jul 2021 14:12:45 +0200 Subject: [PATCH 2/6] Perform some more diagnostics when reparent fails --- src/wine-host/editor.cpp | 110 ++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 42 deletions(-) diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp index 287d0e36..12addab4 100644 --- a/src/wine-host/editor.cpp +++ b/src/wine-host/editor.cpp @@ -349,19 +349,53 @@ Editor::Editor(MainContext& main_context, // of using the XEmbed protocol, we'll register a few events and manage // the child window ourselves. This is a hack to work around the issue's // described in `Editor`'s docstring'. - xcb_void_cookie_t reparent_cookie = xcb_reparent_window_checked( - x11_connection.get(), wine_window, parent_window, 0, 0); - if (std::unique_ptr error( - xcb_request_check(x11_connection.get(), reparent_cookie)); - error) { - std::cerr << "DEBUG: Reparent 1 failed:" << std::endl; - std::cerr << "Error code: " << error->error_code << std::endl; - std::cerr << "Major code: " << error->major_code << std::endl; - std::cerr << "Minor code: " << error->minor_code << std::endl; - } else { - std::cerr << "DEBUG: Reparent 1 succeeded" << std::endl; - } - xcb_flush(x11_connection.get()); + auto do_reparent = [&]() { + const xcb_void_cookie_t reparent_cookie = + xcb_reparent_window_checked(x11_connection.get(), wine_window, + parent_window, 0, 0); + if (std::unique_ptr reparent_error( + xcb_request_check(x11_connection.get(), reparent_cookie)); + reparent_error) { + std::cerr << "DEBUG: Reparent failed:" << std::endl; + std::cerr << "Error code: " << reparent_error->error_code + << std::endl; + std::cerr << "Major code: " << reparent_error->major_code + << std::endl; + std::cerr << "Minor code: " << reparent_error->minor_code + << std::endl; + + // Let's just check all of the reasons why the reparent could + // fail according to the spec in advance + xcb_generic_error_t* error = nullptr; + const xcb_query_pointer_cookie_t query_pointer_cookie = + xcb_query_pointer(x11_connection.get(), wine_window); + const std::unique_ptr + query_pointer_reply(xcb_query_pointer_reply( + x11_connection.get(), query_pointer_cookie, &error)); + if (error) { + free(error); + std::cerr << "DEBUG: Could not query pointer location" + << std::endl; + } else { + if (query_pointer_reply->same_screen) { + std::cerr + << "DEBUG: Pointer is on the same screen as the " + "Wine window, good" + << std::endl; + } else { + std::cerr + << "DEBUG: Pointer is not on the same screen as " + "the Wine window, oh no" + << std::endl; + } + } + } else { + std::cerr << "DEBUG: Reparent succeeded" << std::endl; + } + xcb_flush(x11_connection.get()); + }; + + do_reparent(); // If we're using the double embedding option, then the child window // should only be created after the parent window is visible @@ -387,19 +421,10 @@ Editor::Editor(MainContext& main_context, // trying! // // https://github.com/robbert-vdh/yabridge/issues/40 - reparent_cookie = xcb_reparent_window_checked( - x11_connection.get(), wine_window, parent_window, 0, 0); - if (std::unique_ptr error( - xcb_request_check(x11_connection.get(), reparent_cookie)); - error) { - std::cerr << "DEBUG: Reparent 2 failed:" << std::endl; - std::cerr << "Error code: " << error->error_code << std::endl; - std::cerr << "Major code: " << error->major_code << std::endl; - std::cerr << "Minor code: " << error->minor_code << std::endl; - } else { - std::cerr << "DEBUG: Reparent 2 succeeded" << std::endl; - } - xcb_flush(x11_connection.get()); + std::cerr + << "DEBUG: Reparent 2 is allowed to fail if the first one succeeded" + << std::endl; + do_reparent(); } } @@ -428,11 +453,12 @@ void Editor::handle_x11_events() noexcept { // check if the host's window has changed whenever the // parent window gets reparented. case XCB_REPARENT_NOTIFY: { + const auto event = + reinterpret_cast( + generic_event.get()); + std::cerr << "DEBUG: ReparentNotify for window " - << reinterpret_cast( - generic_event.get()) - ->window - << std::endl; + << event->window << std::endl; redetect_host_window(); } break; @@ -445,12 +471,12 @@ void Editor::handle_x11_events() noexcept { // check is sometimes necessary for using multiple editor // windows within a single plugin group. case XCB_CONFIGURE_NOTIFY: { - std::cerr - << "DEBUG: ConfigureNotify for window " - << reinterpret_cast( - generic_event.get()) - ->window - << std::endl; + const auto event = + reinterpret_cast( + generic_event.get()); + + std::cerr << "DEBUG: ConfigureNotify for window " + << event->window << std::endl; if (!use_xembed) { fix_local_coordinates(); @@ -460,12 +486,12 @@ void Editor::handle_x11_events() noexcept { // since most hosts will only show the window after the plugin // has embedded itself into it. case XCB_VISIBILITY_NOTIFY: { - std::cerr - << "DEBUG: VisibilityNotify for window " - << reinterpret_cast( - generic_event.get()) - ->window - << std::endl; + const auto event = + reinterpret_cast( + generic_event.get()); + + std::cerr << "DEBUG: VisibilityNotify for window " + << event->window << std::endl; if (use_xembed) { do_xembed(); From 0f75461379295d89d50d3d39d1e7aaa16e126b5f Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 20 Jul 2021 00:56:38 +0200 Subject: [PATCH 3/6] Check the windows IDs when handling X11 events This seems like a good idea now that we're listening to more and more events. --- src/wine-host/editor.cpp | 48 +++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp index 12addab4..8d79457e 100644 --- a/src/wine-host/editor.cpp +++ b/src/wine-host/editor.cpp @@ -458,7 +458,9 @@ void Editor::handle_x11_events() noexcept { generic_event.get()); std::cerr << "DEBUG: ReparentNotify for window " - << event->window << std::endl; + << event->window << " to new parent " + << event->parent << ", generated from " + << event->event << std::endl; redetect_host_window(); } break; @@ -478,8 +480,11 @@ void Editor::handle_x11_events() noexcept { std::cerr << "DEBUG: ConfigureNotify for window " << event->window << std::endl; - if (!use_xembed) { - fix_local_coordinates(); + if (event->window == host_window || + event->window == parent_window) { + if (!use_xembed) { + fix_local_coordinates(); + } } } break; // Start the XEmbed procedure when the window becomes visible, @@ -493,8 +498,11 @@ void Editor::handle_x11_events() noexcept { std::cerr << "DEBUG: VisibilityNotify for window " << event->window << std::endl; - if (use_xembed) { - do_xembed(); + if (event->window == host_window || + event->window == parent_window) { + if (use_xembed) { + do_xembed(); + } } } break; // We want to grab keyboard input focus when the user hovers @@ -511,18 +519,20 @@ void Editor::handle_x11_events() noexcept { fix_local_coordinates(); } + const xcb_window_t window = + event_type == XCB_ENTER_NOTIFY + ? reinterpret_cast( + generic_event.get()) + ->child + : reinterpret_cast( + generic_event.get()) + ->event; + if (event_type == XCB_ENTER_NOTIFY) { - std::cerr - << "DEBUG: EnterNotify for window " - << reinterpret_cast( - generic_event.get()) - ->event - << std::endl; + std::cerr << "DEBUG: EnterNotify for window " << window + << std::endl; } else { - std::cerr << "DEBUG: FocusIn for window " - << reinterpret_cast( - generic_event.get()) - ->event + std::cerr << "DEBUG: FocusIn for window " << window << std::endl; } @@ -530,7 +540,8 @@ void Editor::handle_x11_events() noexcept { // `_NET_ACTIVE_WINDOW`, a more naive focus grabbing method // implemented in the `WM_PARENTNOTIFY` handler will be // used. - if (supports_ewmh_active_window() && + if (window == wine_window && + supports_ewmh_active_window() && is_wine_window_active()) { set_input_focus(true); } @@ -548,7 +559,7 @@ void Editor::handle_x11_events() noexcept { generic_event.get()); std::cerr << "DEBUG: LeaveNotify for window " - << event->event << std::endl; + << event->child << std::endl; // This extra check for the `NonlinearVirtual` detail is // important (see @@ -560,7 +571,8 @@ void Editor::handle_x11_events() noexcept { // with an actual Win32 dropdown menu). Without this check // these fake dropdowns would immediately close when // hovering over them. - if (event->detail != XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL && + if (event->child == wine_window && + event->detail != XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL && supports_ewmh_active_window() && is_wine_window_active()) { set_input_focus(false); From 8fbc13fc25d67efb017c2c37affe1949dbb13878 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 20 Jul 2021 01:04:10 +0200 Subject: [PATCH 4/6] Steal the window back when the WM reparents it I've seen this happen once or twice. Earlier on (in #40) we could get away with just reparenting the window another time. But here both reparents succeed, and the issue still happens. But a reparent notify for `parent_window` did appear on system affected by this issue, which is very odd. Hopefully this will help. --- CHANGELOG.md | 4 ++ src/wine-host/editor.cpp | 127 +++++++++++++++++++++------------------ src/wine-host/editor.h | 5 ++ 3 files changed, 78 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2c35764..2b7f11f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,10 @@ Versioning](https://semver.org/spec/v2.0.0.html). like FrozenPlain **Obelisk** would result in a crash. - Fixed a regression from yabridge 3.4.0 where JUCE-based VST3 plugins might cause **Ardour** or **Mixbus** to freeze in very specific circumstances. +- When the window manager somehow steals yabridge's window away from the host, + yabridge will now try to steal it back and reparent it to the host's window + again. This very rarely happened with some window managers, like XFWM, and + only in certain DAWs like **Ardour**. - Worked around a **REAPER** bug that would cause REAPER to not process any keyboard input when the FX window is active but the mouse is outside of the window. We now use the same validation used in `xprop` and `xwininfo` to find diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp index 8d79457e..3947a6a9 100644 --- a/src/wine-host/editor.cpp +++ b/src/wine-host/editor.cpp @@ -63,6 +63,12 @@ constexpr uint32_t parent_event_mask = host_event_mask | XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW; +/** + * The X11 event mask for the Wine window. We'll use this to detect if the + * Window manager somehow steals the Wine window. + */ +constexpr uint32_t wine_event_mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY; + /** * The name of the X11 property on the root window used to denote the active * window in EWMH compliant window managers. @@ -325,13 +331,18 @@ Editor::Editor(MainContext& main_context, // or resized, and when the user moves his mouse over the window because // this is sometimes needed for plugin groups. We also listen for // EnterNotify and LeaveNotify events on the Wine window so we can grab and - // release input focus as necessary. + // release input focus as necessary. And lastly we'll look out for + // reparents, so we can make sure that the window does not get stolen by the + // window manager and that we correctly handle the host reparenting + // `parent_window` themselves. // If we do enable XEmbed support, we'll also listen for visibility changes // and trigger the embedding when the window becomes visible xcb_change_window_attributes(x11_connection.get(), host_window, XCB_CW_EVENT_MASK, &host_event_mask); xcb_change_window_attributes(x11_connection.get(), parent_window, XCB_CW_EVENT_MASK, &parent_event_mask); + xcb_change_window_attributes(x11_connection.get(), wine_window, + XCB_CW_EVENT_MASK, &wine_event_mask); xcb_flush(x11_connection.get()); std::cerr << "DEBUG: host_window: " << host_window << std::endl; @@ -349,52 +360,6 @@ Editor::Editor(MainContext& main_context, // of using the XEmbed protocol, we'll register a few events and manage // the child window ourselves. This is a hack to work around the issue's // described in `Editor`'s docstring'. - auto do_reparent = [&]() { - const xcb_void_cookie_t reparent_cookie = - xcb_reparent_window_checked(x11_connection.get(), wine_window, - parent_window, 0, 0); - if (std::unique_ptr reparent_error( - xcb_request_check(x11_connection.get(), reparent_cookie)); - reparent_error) { - std::cerr << "DEBUG: Reparent failed:" << std::endl; - std::cerr << "Error code: " << reparent_error->error_code - << std::endl; - std::cerr << "Major code: " << reparent_error->major_code - << std::endl; - std::cerr << "Minor code: " << reparent_error->minor_code - << std::endl; - - // Let's just check all of the reasons why the reparent could - // fail according to the spec in advance - xcb_generic_error_t* error = nullptr; - const xcb_query_pointer_cookie_t query_pointer_cookie = - xcb_query_pointer(x11_connection.get(), wine_window); - const std::unique_ptr - query_pointer_reply(xcb_query_pointer_reply( - x11_connection.get(), query_pointer_cookie, &error)); - if (error) { - free(error); - std::cerr << "DEBUG: Could not query pointer location" - << std::endl; - } else { - if (query_pointer_reply->same_screen) { - std::cerr - << "DEBUG: Pointer is on the same screen as the " - "Wine window, good" - << std::endl; - } else { - std::cerr - << "DEBUG: Pointer is not on the same screen as " - "the Wine window, oh no" - << std::endl; - } - } - } else { - std::cerr << "DEBUG: Reparent succeeded" << std::endl; - } - xcb_flush(x11_connection.get()); - }; - do_reparent(); // If we're using the double embedding option, then the child window @@ -414,17 +379,6 @@ Editor::Editor(MainContext& main_context, ShowWindow(win32_child_window->handle, SW_SHOWNORMAL); } - - // HACK: I can't seem to figure why the initial reparent would fail on - // this particular i3 config in a way that I'm unable to - // reproduce, but if it doesn't work the first time, just keep - // trying! - // - // https://github.com/robbert-vdh/yabridge/issues/40 - std::cerr - << "DEBUG: Reparent 2 is allowed to fail if the first one succeeded" - << std::endl; - do_reparent(); } } @@ -463,6 +417,21 @@ void Editor::handle_x11_events() noexcept { << event->event << std::endl; redetect_host_window(); + + // NOTE: Some window managers like to steal the window, so + // we must prevent that. This situation is easily + // recognized since the window will then cover the + // entire screen (since that's what the client area + // has been set to). + if (event->window == parent_window || + (event->window == wine_window && + event->parent != parent_window)) { + if (use_xembed) { + do_xembed(); + } else { + do_reparent(); + } + } } break; // We're listening for `ConfigureNotify` events on the host's // window (i.e. the window that's actually going to get dragged @@ -816,6 +785,48 @@ void Editor::send_xembed_message(xcb_window_t window, reinterpret_cast(&event)); } +void Editor::do_reparent() const { + // TODO: When rebasing this, we should keep in the error logging for when + // the reparent fails + const xcb_void_cookie_t reparent_cookie = xcb_reparent_window_checked( + x11_connection.get(), wine_window, parent_window, 0, 0); + if (std::unique_ptr reparent_error( + xcb_request_check(x11_connection.get(), reparent_cookie)); + reparent_error) { + std::cerr << "DEBUG: Reparent failed:" << std::endl; + std::cerr << "Error code: " << reparent_error->error_code << std::endl; + std::cerr << "Major code: " << reparent_error->major_code << std::endl; + std::cerr << "Minor code: " << reparent_error->minor_code << std::endl; + + // Let's just check all of the reasons why the reparent could + // fail according to the spec in advance + xcb_generic_error_t* error = nullptr; + const xcb_query_pointer_cookie_t query_pointer_cookie = + xcb_query_pointer(x11_connection.get(), wine_window); + const std::unique_ptr query_pointer_reply( + xcb_query_pointer_reply(x11_connection.get(), query_pointer_cookie, + &error)); + if (error) { + free(error); + std::cerr << "DEBUG: Could not query pointer location" << std::endl; + } else { + if (query_pointer_reply->same_screen) { + std::cerr << "DEBUG: Pointer is on the same screen as the " + "Wine window, good" + << std::endl; + } else { + std::cerr << "DEBUG: Pointer is not on the same screen as " + "the Wine window, oh no" + << std::endl; + } + } + } else { + std::cerr << "DEBUG: Reparent succeeded" << std::endl; + } + + xcb_flush(x11_connection.get()); +} + void Editor::do_xembed() const { if (!use_xembed) { return; diff --git a/src/wine-host/editor.h b/src/wine-host/editor.h index f09a3865..8b16471b 100644 --- a/src/wine-host/editor.h +++ b/src/wine-host/editor.h @@ -245,6 +245,11 @@ class Editor { uint32_t data1, uint32_t data2) const noexcept; + /** + * Reparent `wine_window` to `parent_window`. This includes the flush. + */ + void do_reparent() const; + /** * Start the XEmbed procedure when `use_xembed` is enabled. This should be * rerun whenever visibility changes. From f2ffb68b553446e3205062b7413e2a003e3bb144 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 15 Jun 2021 13:16:50 +0200 Subject: [PATCH 5/6] Attempt to fix rare multiple displays issue (cherry picked from 1950206159fbc830718803fa152b636b2a914a95) Under certain DEs/WMs, the window might not render at all when using multiple displays and the primary display is set to the rightmost display. This seems like a reasonably candidate for fixing this. https://github.com/robbert-vdh/yabridge/issues/89 https://github.com/robbert-vdh/yabridge/issues/104 --- CHANGELOG.md | 7 +++++++ src/wine-host/editor.cpp | 23 ++++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b7f11f5..929124cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,13 @@ Versioning](https://semver.org/spec/v2.0.0.html). yabridge will now try to steal it back and reparent it to the host's window again. This very rarely happened with some window managers, like XFWM, and only in certain DAWs like **Ardour**. +- Possibly fixed an obscure error where the editor would not render when using + multiple displays, and the rightmost display was set as primary. This issue is + very rare, and I haven't gotten any response back when I asked the people + affected by this to test a potential fix, so I'm just including it in yabridge + proper in case it helps (it should at least not make anything worse). If + anyone was affected by this, please let me know if this patch makes any + difference! - Worked around a **REAPER** bug that would cause REAPER to not process any keyboard input when the FX window is active but the mouse is outside of the window. We now use the same validation used in `xprop` and `xwininfo` to find diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp index 3947a6a9..5206e459 100644 --- a/src/wine-host/editor.cpp +++ b/src/wine-host/editor.cpp @@ -257,8 +257,21 @@ Editor::Editor(MainContext& main_context, reinterpret_cast(get_window_class()), "yabridge plugin", WS_POPUP, - CW_USEDEFAULT, - CW_USEDEFAULT, + // NOTE: With certain DEs/WMs (notably, + // Cinnamon), Wine does not render the + // window at all when using a primary + // display that's positioned to the + // right of another display. Presumably + // it tries to manually clip the client + // rendered client area to the physical + // display. During the reparenting and + // `fix_local_coordinates()` the window + // will be moved to `(0, 0)` anyways, + // but setting its initial position + // according to the primary display + // fixes these rendering issues. + GetSystemMetrics(SM_XVIRTUALSCREEN), + GetSystemMetrics(SM_YVIRTUALSCREEN), client_area.width, client_area.height, nullptr, @@ -372,9 +385,9 @@ Editor::Editor(MainContext& main_context, main_context, x11_connection, CreateWindowEx(WS_EX_TOOLWINDOW, reinterpret_cast(get_window_class()), - "yabridge plugin child", WS_CHILD, CW_USEDEFAULT, - CW_USEDEFAULT, client_area.width, - client_area.height, win32_window.handle, nullptr, + "yabridge plugin child", WS_CHILD, 0, 0, + client_area.width, client_area.height, + win32_window.handle, nullptr, GetModuleHandle(nullptr), this)); ShowWindow(win32_child_window->handle, SW_SHOWNORMAL); From db8eb5b6781e2c58e8cf4867d45683ab2ceb48de Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 20 Jul 2021 01:31:24 +0200 Subject: [PATCH 6/6] Add a todo about the editor debug level --- src/wine-host/editor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wine-host/editor.cpp b/src/wine-host/editor.cpp index 5206e459..e11b8a38 100644 --- a/src/wine-host/editor.cpp +++ b/src/wine-host/editor.cpp @@ -400,6 +400,8 @@ void Editor::handle_x11_events() noexcept { // the window is unmapped `wine_window` doesn't exist and any X11 // function calls involving it will fail. All functions called from // here should be able to handle that cleanly. + // TODO: Move all debug messages to a special editor debug level, which + // should be specified as +editor try { std::unique_ptr generic_event; while (generic_event.reset(xcb_poll_for_event(x11_connection.get())),