Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: [6.1.7 - 7.0.10] repaint issue: InvalidateRect() called with wrong rect size if coming from keyboard hook #1366

Open
1 task done
dsp56300 opened this issue Mar 23, 2024 · 0 comments

Comments

@dsp56300
Copy link

Detailed steps on how to reproduce the bug

We have the issue that our plugin has repaint issues if a juce::List is repainted due to key up/down presses, selecting a row via mouse is fine. It only happens in Bitwig VST2/VST3 and a Windows 10/11 DPI scale of 125%.

It was quite some work to track this down, here is the result:

The reason for this is that the function static RECT getWindowClientRect (HWND hwnd) returns a different window size if its called from the keyboardHookCallback() compared to being called from the windowProc()

Example result when called from the keyboardHookCallback:

GetWindowRect HWND=00590fcc 88 1977 3296 738 MapWindowPoints HWND=00590fcc 0 0 1319 650

Example result when called from the windowProc:

GetWindowRect HWND=00590fcc 110 1991 3640 923 MapWindowPoints HWND=00590fcc 0 0 1649 813

If we do the math, we can see that the reported window size for the keyboard hook compared to the windowProc is 100/125 too small, exactly the inverse of the DPI setting.

This causes all internalRepaint() calls to report a downscaled rectangle to the win32 function InvalidateRect(). As Win32 responds with WM_PAINT messages via windowProc (where the reported window size is correct again), the redraw regions are all messed up.

Unfortunately I do not know enough about Win32 programming to provide a fix on my own, I can only assume that Windows is not aware of the current DPI setting when being called from the keyboard hook.

Hope this helps.

What is the expected behaviour?

The invalidated regions should have the correct positions & sizes, regardless of any DPI setting

Operating systems

Windows

What versions of the operating systems?

Tested on Windows 11 & Windows 10

Architectures

x86_64

Stacktrace

KEYBOARD VERSION
OsTIrus.dll!juce::HWNDComponentPeer::getBounds::__l2::<lambda>() Line 1852	C++
OsTIrus.dll!juce::HWNDComponentPeer::getBounds() Line 1855	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1627	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::repaint() Line 1579	C++
OsTIrus.dll!juce::ComponentWithListRowMouseBehaviours<juce::ListBox::RowComponent>::updateRowAndSelection(const int newRow, const bool nowSelected) Line 82	C++
OsTIrus.dll!juce::ListBox::RowComponent::update(const int newRow, const bool nowSelected) Line 170	C++
OsTIrus.dll!juce::ListBox::ListViewport::updateContents() Line 409	C++
OsTIrus.dll!juce::ListBox::ListViewport::selectRow(const int row, const int rowH, const bool dontScroll, const int lastSelectedRow, const int totalRows, const bool isMouseClick) Line 454	C++
OsTIrus.dll!juce::ListBox::selectRowInternal(int row, bool dontScroll, bool deselectOthersFirst, bool isMouseClick) Line 698	C++
OsTIrus.dll!juce::ListBox::selectRow(int row, bool dontScroll, bool deselectOthersFirst) Line 670	C++
OsTIrus.dll!juce::ListBox::keyPressed(const juce::KeyPress & key) Line 935	C++
OsTIrus.dll!juce::ComponentPeer::handleKeyPress(const juce::KeyPress & keyInfo) Line 206	C++
OsTIrus.dll!juce::ComponentPeer::handleKeyPress(int keyCode, unsigned int textCharacter) Line 180	C++
OsTIrus.dll!juce::HWNDComponentPeer::doKeyDown(const unsigned __int64 key) Line 3576	C++
OsTIrus.dll!juce::HWNDComponentPeer::offerKeyMessageToJUCEWindow(const tagMSG & msg) Line 2386	C++
OsTIrus.dll!juce::detail::WindowsHooks::Hooks::keyboardHookCallback(int nCode, unsigned __int64 wParam, __int64 lParam) Line 75	C++
user32.dll!00007ffe523a78a4()	Unknown
user32.dll!00007ffe523a494f()	Unknown
user32.dll!00007ffe523a4896()	Unknown
ntdll.dll!00007ffe53f333b4()	Unknown
win32u.dll!00007ffe51bb1534()	Unknown
user32.dll!00007ffe523a535a()	Unknown
BitwigPluginHost-X64-SSE41.exe!000000014003f4cd()	Unknown
BitwigPluginHost-X64-SSE41.exe!000000014000f1bc()	Unknown
BitwigPluginHost-X64-SSE41.exe!00000001400ddc94()	Unknown
kernel32.dll!00007ffe5295257d()	Unknown
ntdll.dll!00007ffe53eeaa58()	Unknown

MOUSE VERSION
OsTIrus.dll!juce::HWNDComponentPeer::getBounds::__l2::<lambda>() Line 1852	C++
OsTIrus.dll!juce::HWNDComponentPeer::getBounds() Line 1855	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1627	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::internalRepaint(juce::Rectangle<int> area) Line 1603	C++
OsTIrus.dll!juce::Component::internalRepaintUnchecked(juce::Rectangle<int> area, bool isEntireComponent) Line 1639	C++
OsTIrus.dll!juce::Component::repaint() Line 1579	C++
OsTIrus.dll!juce::ComponentWithListRowMouseBehaviours<juce::ListBox::RowComponent>::updateRowAndSelection(const int newRow, const bool nowSelected) Line 82	C++
OsTIrus.dll!juce::ListBox::RowComponent::update(const int newRow, const bool nowSelected) Line 170	C++
OsTIrus.dll!juce::ListBox::ListViewport::updateContents() Line 409	C++
OsTIrus.dll!juce::ListBox::ListViewport::selectRow(const int row, const int rowH, const bool dontScroll, const int lastSelectedRow, const int totalRows, const bool isMouseClick) Line 454	C++
OsTIrus.dll!juce::ListBox::selectRowInternal(int row, bool dontScroll, bool deselectOthersFirst, bool isMouseClick) Line 698	C++
OsTIrus.dll!juce::ListBox::selectRowsBasedOnModifierKeys(int row, juce::ModifierKeys mods, bool isMouseUpEvent) Line 816	C++
OsTIrus.dll!juce::ListBox::RowComponent::performSelection(const juce::MouseEvent & e, bool isMouseUp) Line 194	C++
OsTIrus.dll!juce::ComponentWithListRowMouseBehaviours<juce::ListBox::RowComponent>::mouseUp(const juce::MouseEvent & e) Line 106	C++
OsTIrus.dll!juce::Component::internalMouseUp(juce::MouseInputSource source, const juce::detail::PointerState & relativePointerState, juce::Time time, juce::ModifierKeys oldModifiers) Line 2227	C++
OsTIrus.dll!juce::detail::MouseInputSourceImpl::sendMouseUp(juce::Component & comp, const juce::detail::PointerState & pointerState, juce::Time time, juce::ModifierKeys oldMods) Line 155	C++
OsTIrus.dll!juce::detail::MouseInputSourceImpl::setButtons(const juce::detail::PointerState & pointerState, juce::Time time, juce::ModifierKeys newButtonState) Line 206	C++
OsTIrus.dll!juce::detail::MouseInputSourceImpl::handleEvent(juce::ComponentPeer & newPeer, juce::Point<float> positionWithinPeer, juce::Time time, const juce::ModifierKeys newMods, float newPressure, float newOrientation, juce::PenDetails pen) Line 331	C++
OsTIrus.dll!juce::MouseInputSource::handleEvent(juce::ComponentPeer & peer, juce::Point<float> pos, __int64 time, juce::ModifierKeys mods, float pressure, float orientation, const juce::PenDetails & penDetails) Line 81	C++
OsTIrus.dll!juce::ComponentPeer::handleMouseEvent(juce::MouseInputSource::InputSourceType type, juce::Point<float> pos, juce::ModifierKeys newMods, float newPressure, float newOrientation, __int64 time, juce::PenDetails pen, int touchIndex) Line 90	C++
OsTIrus.dll!juce::HWNDComponentPeer::doMouseEvent(juce::Point<float> position, float pressure, float orientation, juce::ModifierKeys mods) Line 2999	C++
OsTIrus.dll!juce::HWNDComponentPeer::doMouseUp(juce::Point<float> position, const unsigned __int64 wParam) Line 3174	C++
OsTIrus.dll!juce::HWNDComponentPeer::peerWindowProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 4079	C++
OsTIrus.dll!juce::HWNDComponentPeer::windowProc(HWND__ * h, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 3974	C++
user32.dll!00007ffe52398241()	Unknown
user32.dll!00007ffe52397d01()	Unknown
BitwigPluginHost-X64-SSE41.exe!000000014003f56e()	Unknown
BitwigPluginHost-X64-SSE41.exe!000000014000f1bc()	Unknown
BitwigPluginHost-X64-SSE41.exe!00000001400ddc94()	Unknown
kernel32.dll!00007ffe5295257d()	Unknown
ntdll.dll!00007ffe53eeaa58()	Unknown

Plug-in formats (if applicable)

VST2, VST3

Plug-in host applications (DAWs) (if applicable)

Bitwig Studio 5.1.3

Testing on the develop branch

The bug is present on the develop branch

Code of Conduct

  • I agree to follow the Code of Conduct
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant