Fix right-click context menus dismissing before they can be read (GTK) (#1437)
* Defer Voice Keyer right-click menu popup via CallAfter On GTK, PopupMenu() called synchronously from the wxEVT_CONTEXT_MENU handler opens the menu while the originating right-click's implicit pointer grab is still active, so the matching button-up is delivered straight to the menu, selecting whatever is under the cursor before it can be read. Deferring via CallAfter lets the initiating click fully complete first. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix Voice Keyer/PTT right-click menu using established RIGHT_UP workaround The CallAfter approach in the previous commit didn't help: on a fast click, GDK often has both the button-press and its paired release already queued and dispatches both before any idle-priority callback runs, so the menu still opened with the click already spent. This file already has the correct fix for the identical issue on other widgets (m_txLevelBox, m_txtTxLevelNum, m_btnTogTune, added earlier): on wxGTK 3.3+, wxEVT_CONTEXT_MENU is generated from button-press, so showing a menu from it opens while that click's release is still pending and GTK delivers the release straight to the menu as a selection. Bind wxEVT_RIGHT_UP instead for wx>=3.3 (keeping wxEVT_CONTEXT_MENU on older wx, matching the existing widgets), which only fires once the click has genuinely finished. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Fix FreeDV Reporter Send/Clear button right-click menus (same RIGHT_UP fix) Same class of bug as the Voice Keyer/PTT buttons: wxEVT_CONTEXT_MENU is generated from button-press on wxGTK 3.3+, so the menu opens while the click's release is still pending and GTK delivers it straight to the menu as a selection. Was only visible when the item under the cursor happened to be enabled -- a disabled item just closes the menu silently on release, masking the bug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Scope the RIGHT_UP context-menu workaround to GTK only The wxEVT_CONTEXT_MENU-on-button-press behaviour this works around is GTK-specific: MSW already generates the event on button-up, and OSX uses ctrl-click. The version-only guard (wxCHECK_VERSION(3,3,0)) would otherwise apply the same override on Windows/Mac builds using wx 3.3+, which could drop keyboard-invoked (Menu key/Shift+F10) context menus on MSW since that only comes through wxEVT_CONTEXT_MENU. Add defined(__WXGTK__) to all six guard sites, including the pre-existing one for m_txLevelBox/m_txtTxLevelNum/m_btnTogTune this pattern was copied from. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Drop version gate: dismiss-on-release bug confirmed present on wx 3.2 too Direct testing on a wxGTK 3.2 build showed the same context-menu dismiss-on-release bug the wxCHECK_VERSION(3,3,0) guard assumed was 3.3-specific (copied from the pre-existing txLevel/tune pattern this was based on). Reading wx 3.2 vs 3.3 source confirmed the press-side event synthesis is identical in both versions, so the fix now applies on all wxGTK versions for these real windowed button widgets. The original txLevel/tune block's version gate is left untouched since its stated rationale (windowless widgets not generating RIGHT_UP pre-3.3) is a separate, more specific concern. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add PR #1437 to changelog. --------- Co-authored-by: Barry Jackson <barjac@mageia.org> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Mooneer Salem <mooneer@gmail.com>pull/1438/head
parent
4a18367084
commit
9918843f4f
|
|
@ -965,7 +965,8 @@ LDPC | Low Density Parity Check Codes - a family of powerful FEC codes
|
|||
* Only preserve previously selected tab on TX if it's in the same group as 'From Mic'. (PR #1428)
|
||||
* Scalar plot label alignment fix for Y axis of Frm Decoder/Mic/Radio, SNR and Spectrum plots. (PR #1429) - thanks @barjac!
|
||||
* Fix window position restore under KWin and labwc (main window + FreeDV Reporter window). (PR #1431, #1433) - thanks @barjac!
|
||||
* Harden experimental tab layout persistence: fix positional index corruption across version upgrades, a crash on malformed saved layouts, incorrect tab restore with split tab groups, a saved layout getting silently overwritten by toggling Experimental Features off then back on before exiting, and a drag-and-drop assertion crash when an old saved layout leaves an empty tab group behind. (PR #1434) - thanks @barjac!
|
||||
* Harden experimental tab layout persistence. (PR #1434) - thanks @barjac!
|
||||
* Fix right-click context menus dismissing before they can be read (GTK) (PR #1437) - thanks @barjac!
|
||||
2. Enhancements:
|
||||
* Add UDP broadcast of received callsigns. (PR #1367)
|
||||
* Add Time-Out Timer (TOT) capability to FreeDV. (PR #1366, #1398, #1405) - thanks @barjac!
|
||||
|
|
|
|||
|
|
@ -628,9 +628,19 @@ FreeDVReporterDialog::FreeDVReporterDialog(wxWindow* parent, wxWindowID id, cons
|
|||
|
||||
m_statusMessage->Connect(wxEVT_TEXT, wxCommandEventHandler(FreeDVReporterDialog::OnStatusTextChange), NULL, this);
|
||||
m_buttonSend->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FreeDVReporterDialog::OnStatusTextSend), NULL, this);
|
||||
m_buttonSend->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(FreeDVReporterDialog::OnStatusTextSendContextMenu), NULL, this);
|
||||
m_buttonClear->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FreeDVReporterDialog::OnStatusTextClear), NULL, this);
|
||||
#if defined(__WXGTK__)
|
||||
// wxGTK fires wxEVT_CONTEXT_MENU on button-press, causing GTK to
|
||||
// dismiss PopupMenu on button release (see topFrame.cpp for the same
|
||||
// workaround on other widgets); use RIGHT_UP instead. MSW/OSX are
|
||||
// unaffected, so this is GTK-specific. Confirmed present on both
|
||||
// wxGTK 3.2 and 3.3+, so no version gate here.
|
||||
m_buttonSend->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent&) { wxContextMenuEvent ctx; OnStatusTextSendContextMenu(ctx); });
|
||||
m_buttonClear->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent&) { wxContextMenuEvent ctx; OnStatusTextClearContextMenu(ctx); });
|
||||
#else
|
||||
m_buttonSend->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(FreeDVReporterDialog::OnStatusTextSendContextMenu), NULL, this);
|
||||
m_buttonClear->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(FreeDVReporterDialog::OnStatusTextClearContextMenu), NULL, this);
|
||||
#endif
|
||||
|
||||
m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FreeDVReporterDialog::OnOK), NULL, this);
|
||||
m_buttonSendQSY->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FreeDVReporterDialog::OnSendQSY), NULL, this);
|
||||
|
|
@ -703,8 +713,10 @@ FreeDVReporterDialog::~FreeDVReporterDialog()
|
|||
m_statusMessage->Disconnect(wxEVT_TEXT, wxCommandEventHandler(FreeDVReporterDialog::OnStatusTextChange), NULL, this);
|
||||
m_buttonSend->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FreeDVReporterDialog::OnStatusTextSend), NULL, this);
|
||||
m_buttonClear->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FreeDVReporterDialog::OnStatusTextClear), NULL, this);
|
||||
#if !defined(__WXGTK__)
|
||||
m_buttonSend->Disconnect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(FreeDVReporterDialog::OnStatusTextSendContextMenu), NULL, this);
|
||||
m_buttonClear->Disconnect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(FreeDVReporterDialog::OnStatusTextClearContextMenu), NULL, this);
|
||||
#endif
|
||||
|
||||
m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FreeDVReporterDialog::OnOK), NULL, this);
|
||||
m_buttonSendQSY->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FreeDVReporterDialog::OnSendQSY), NULL, this);
|
||||
|
|
|
|||
|
|
@ -969,9 +969,21 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
|
|||
m_togBtnOnOff->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnOnOff), NULL, this);
|
||||
m_togBtnAnalog->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnAnalogClick), NULL, this);
|
||||
m_togBtnVoiceKeyer->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnVoiceKeyerClick), NULL, this);
|
||||
m_togBtnVoiceKeyer->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTogBtnVoiceKeyerRightClick), NULL, this);
|
||||
m_btnTogPTT->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnPTT), NULL, this);
|
||||
|
||||
#if defined(__WXGTK__)
|
||||
// wxGTK fires wxEVT_CONTEXT_MENU on button-press for these widgets,
|
||||
// causing GTK to dismiss PopupMenu on button release; use RIGHT_UP
|
||||
// instead. MSW/OSX are unaffected (MSW generates the event on
|
||||
// button-up already; OSX uses ctrl-click), so this is GTK-specific.
|
||||
// Confirmed present on both wxGTK 3.2 and 3.3+, unlike the windowless
|
||||
// widget case below, so no version gate here.
|
||||
m_togBtnVoiceKeyer->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent&) { wxContextMenuEvent ctx; OnTogBtnVoiceKeyerRightClick(ctx); });
|
||||
m_btnTogPTT->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent&) { wxContextMenuEvent ctx; OnTogBtnPTTRightClick(ctx); });
|
||||
#else
|
||||
m_togBtnVoiceKeyer->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTogBtnVoiceKeyerRightClick), NULL, this);
|
||||
m_btnTogPTT->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTogBtnPTTRightClick), NULL, this);
|
||||
#endif
|
||||
|
||||
m_BtnCallSignReset->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnCallSignReset), NULL, this);
|
||||
m_BtnBerReset->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnBerReset), NULL, this);
|
||||
|
|
@ -996,15 +1008,18 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
|
|||
m_btnTxLevelPP->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(TopFrame::OnTxLevelMouseWheel), NULL, this);
|
||||
m_btnTogTune->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(TopFrame::OnTxLevelMouseWheel), NULL, this);
|
||||
|
||||
#if wxCHECK_VERSION(3, 3, 0)
|
||||
#if wxCHECK_VERSION(3, 3, 0) && defined(__WXGTK__)
|
||||
// wxGTK 3.3+ fires wxEVT_CONTEXT_MENU on button-press for these widget types,
|
||||
// causing GTK to dismiss PopupMenu on button release; use RIGHT_UP instead.
|
||||
// MSW/OSX are unaffected (MSW generates the event on button-up already;
|
||||
// OSX uses ctrl-click), so this is GTK-specific.
|
||||
m_txLevelBox->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent&) { wxContextMenuEvent ctx; OnTxLevelContextMenu(ctx); });
|
||||
m_txtTxLevelNum->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent&) { wxContextMenuEvent ctx; OnTxLevelContextMenu(ctx); });
|
||||
m_btnTogTune->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent&) { wxContextMenuEvent ctx; OnTuneAttenContextMenu(ctx); });
|
||||
#else
|
||||
// wxGTK < 3.3 does not generate RIGHT_UP for windowless widget types
|
||||
// (wxStaticBox, wxStaticText); CONTEXT_MENU works without the dismiss issue.
|
||||
// (Also used as-is on MSW/OSX regardless of wx version -- see above.)
|
||||
m_txLevelBox->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTxLevelContextMenu), NULL, this);
|
||||
m_txtTxLevelNum->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTxLevelContextMenu), NULL, this);
|
||||
m_btnTogTune->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTuneAttenContextMenu), NULL, this);
|
||||
|
|
@ -1089,9 +1104,11 @@ TopFrame::~TopFrame()
|
|||
m_togBtnOnOff->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnOnOff), NULL, this);
|
||||
m_togBtnAnalog->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnAnalogClick), NULL, this);
|
||||
m_togBtnVoiceKeyer->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnVoiceKeyerClick), NULL, this);
|
||||
m_togBtnVoiceKeyer->Disconnect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTogBtnVoiceKeyerRightClick), NULL, this);
|
||||
m_btnTogPTT->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnPTT), NULL, this);
|
||||
#if !defined(__WXGTK__)
|
||||
m_togBtnVoiceKeyer->Disconnect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTogBtnVoiceKeyerRightClick), NULL, this);
|
||||
m_btnTogPTT->Disconnect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTogBtnPTTRightClick), NULL, this);
|
||||
#endif
|
||||
|
||||
m_btnCenterRx->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnCenterRx), NULL, this);
|
||||
|
||||
|
|
@ -1108,7 +1125,7 @@ TopFrame::~TopFrame()
|
|||
m_btnTxLevelM->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTxLevelDecr), NULL, this);
|
||||
m_btnTxLevelP->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTxLevelIncr), NULL, this);
|
||||
m_btnTxLevelPP->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTxLevelIncrBig), NULL, this);
|
||||
#if !wxCHECK_VERSION(3, 3, 0)
|
||||
#if !(wxCHECK_VERSION(3, 3, 0) && defined(__WXGTK__))
|
||||
m_txLevelBox->Disconnect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTxLevelContextMenu), NULL, this);
|
||||
m_txtTxLevelNum->Disconnect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTxLevelContextMenu), NULL, this);
|
||||
m_btnTogTune->Disconnect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(TopFrame::OnTuneAttenContextMenu), NULL, this);
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ class TopFrame : public wxFrame
|
|||
virtual void OnTogBtnAnalogClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnTogBtnVoiceKeyerClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnTogBtnVoiceKeyerRightClick( wxContextMenuEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
virtual void OnTogBtnPTT( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnTogBtnPTTRightClick( wxContextMenuEvent& event ) { event.Skip(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ void MainFrame::OnTogBtnVoiceKeyerRightClick( wxContextMenuEvent& )
|
|||
bool enabled = vk_state == VK_IDLE && !m_btnTogPTT->GetValue();
|
||||
chooseVKFileMenuItem_->Enable(vk_state == VK_IDLE);
|
||||
recordNewVoiceKeyerFileMenuItem_->Enable(enabled);
|
||||
|
||||
|
||||
// Trigger right-click menu popup in a location that will prevent it from
|
||||
// ending up off the screen.
|
||||
auto sz = m_togBtnVoiceKeyer->GetSize();
|
||||
|
|
|
|||
Loading…
Reference in New Issue