From f5d264287432b7b2c3458624bf3fbc6fd065221f Mon Sep 17 00:00:00 2001 From: attila Date: Fri, 1 Jul 2022 21:15:00 +0200 Subject: [PATCH] Linux: Fix resizing issue with the PopupMenu Previously opening a PopupMenu and then clicking somewhere outside the application would cause the mouse button representation to be stuck in a down state. --- .../native/x11/juce_linux_XWindowSystem.cpp | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp b/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp index 5ef06a28d0..da1a27308e 100644 --- a/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp +++ b/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp @@ -413,6 +413,31 @@ namespace Keys static bool capsLock = false; static char keyStates [32]; static constexpr int extendedKeyModifier = 0x10000000; + static bool modifierKeysAreStale = false; + + static void refreshStaleModifierKeys() + { + if (modifierKeysAreStale) + { + XWindowSystem::getInstance()->getNativeRealtimeModifiers(); + modifierKeysAreStale = false; + } + } + + // Call this function when only the mouse keys need to be refreshed e.g. when the event + // parameter already has information about the keys. + static void refreshStaleMouseKeys() + { + if (modifierKeysAreStale) + { + const auto oldMods = ModifierKeys::currentModifiers; + XWindowSystem::getInstance()->getNativeRealtimeModifiers(); + ModifierKeys::currentModifiers = oldMods.withoutMouseButtons() + .withFlags (ModifierKeys::currentModifiers.withOnlyMouseButtons() + .getRawFlags()); + modifierKeysAreStale = false; + } + } } const int KeyPress::spaceKey = XK_space & 0xff; @@ -2448,6 +2473,18 @@ ModifierKeys XWindowSystem::getNativeRealtimeModifiers() const ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (mouseMods); + // We are keeping track of the state of modifier keys and mouse buttons with the assumption that + // for every mouse down we are going to receive a mouse up etc. + // + // This assumption is broken when getNativeRealtimeModifiers() is called. If for example we call + // this function when the mouse cursor is in another application and the mouse button happens to + // be down, then its represented state in currentModifiers may remain down indefinitely, since + // we aren't going to receive an event when it's released. + // + // We mark this state in this variable, and we can restore synchronization when our window + // receives an event again. + Keys::modifierKeysAreStale = true; + return ModifierKeys::currentModifiers; } @@ -3310,6 +3347,7 @@ void XWindowSystem::handleWindowMessage (LinuxComponentPeer* peer, XEvent& event void XWindowSystem::handleKeyPressEvent (LinuxComponentPeer* peer, XKeyEvent& keyEvent) const { auto oldMods = ModifierKeys::currentModifiers; + Keys::refreshStaleModifierKeys(); char utf8 [64] = { 0 }; juce_wchar unicodeChar = 0; @@ -3540,6 +3578,7 @@ void XWindowSystem::handleButtonReleaseEvent (LinuxComponentPeer* peer, const XB void XWindowSystem::handleMotionNotifyEvent (LinuxComponentPeer* peer, const XPointerMovedEvent& movedEvent) const { updateKeyModifiers ((int) movedEvent.state); + Keys::refreshStaleMouseKeys(); auto& dragState = dragAndDropStateMap[peer];