Developer forums (C::B DEVELOPMENT STRICTLY!) > CodeCompletion redesign

question on how to trigger evt(cbEVT_COMPLETE_CODE)

<< < (3/5) > >>

ollydbg:

--- Quote from: ollydbg on August 19, 2017, 09:14:27 am ---Guys, I found another bug under C::B build against wx3.1, that is "press shift + key" cancel the auto completion window under Windows. I test it again, and this does not happens under Nightly build version. I'm on Win7.

Test code is in the post: Re: question on how to trigger evt(cbEVT_COMPLETE_CODE), the step to reproduce is quite simple:

1, hit "." after the "obj", which shows the suggestion list.
2, hit "shift + m"
3, the expected behavior is the "Method.." item will be selected, but in my C::B build against wx3.1, the auto completion window is canceled.

Note that if in the step 2, I hit the "a", then the "a..." item is selected, and the auto completion window is still active.
Note that if in the step 2, I only hit the "shift" key, the auto completion window is still active.

Really strange, it looks like wx3.1 emit some extra event which cancel the active auto completion window when I hit "shift + key". Any one can reproduce?

--- End quote ---

I found more annoying issue, sometimes, when I hit the "." key, the suggestion list won't happens, because a void CCManager::OnAutocompleteHide(wxShowEvent& event) event always happens after the hit, thus a user can't see the suggestion list.

@Alhpa, can you explain some logic about this piece of the code(how the suggestion list is shown, and how a non-focus window is shown, and how the doxygen html window is shown, in my test case, I don't have any doxygen style comments in the code), it is a bit hard to understand, thanks.

EDIT

--- Code: ---void CCManager::OnAutocompleteSelect(wxListEvent& event)
{
    event.Skip();
    m_AutocompSelectTimer.Start(AUTOCOMP_SELECT_DELAY, wxTIMER_ONE_SHOT);
    wxObject* evtObj = event.GetEventObject();
    if (!evtObj)
        return;
#ifdef __WXMSW__
    m_pAutocompPopup = static_cast<wxListView*>(evtObj);
#endif // __WXMSW__

    wxWindow* evtWin = static_cast<wxWindow*>(evtObj)->GetParent();
    if (!evtWin)
        return;
...

--- End code ---
Why we have a special m_pAutocompPopup variable for Windows platform?
What is the window hireachy about those variables?(m_pAutocompPopup, m_pPopup, m_pHtml, and the native CClist)

Alpha:
Under Windows, scroll events are always directed to the window in focus, making it difficult to scroll the autocomplete list and the doxygen popup with the mouse.  So, under Windows we catch scroll requests to the cbStyledTextCtrl, and run them through CCManager::OnPopupScroll().  This filters the event, and if the mouse is over the autocomplete list or the doxygen popup, the scroll event is instead sent there (and skipped for the editor window).

m_pAutocompPopup is a handle to the autocomplete list window created by (wx)scintilla, needed under Windows to determine its dimensions (so the scroll event can be sent to it, if relevant).
m_pPopup is the window for the doxygen popup, with properties so it is always on top, but cannot be focused.
m_pHtml is the rendered doxygen documentation to display in the popup.
By native CCList, I assume you are referring to m_AutocompTokens?  It is the data CCManager uses to populate the (wx)scintilla autocomplete list window.

(Also, self plug.  I cross linked our generated documentation, so wxWidgets classes link to their documentation.)

ollydbg:

--- Quote from: Alpha on August 26, 2017, 03:36:58 pm ---Under Windows, scroll events are always directed to the window in focus, making it difficult to scroll the autocomplete list and the doxygen popup with the mouse.  So, under Windows we catch scroll requests to the cbStyledTextCtrl, and run them through CCManager::OnPopupScroll().  This filters the event, and if the mouse is over the autocomplete list or the doxygen popup, the scroll event is instead sent there (and skipped for the editor window).

m_pAutocompPopup is a handle to the autocomplete list window created by (wx)scintilla, needed under Windows to determine its dimensions (so the scroll event can be sent to it, if relevant).
m_pPopup is the window for the doxygen popup, with properties so it is always on top, but cannot be focused.
m_pHtml is the rendered doxygen documentation to display in the popup.
By native CCList, I assume you are referring to m_AutocompTokens?  It is the data CCManager uses to populate the (wx)scintilla autocomplete list window.

(Also, self plug.  I cross linked our generated documentation, so wxWidgets classes link to their documentation.)

--- End quote ---

Thanks for the explanation.

Well, I debugged for several hours, and I still can't find where does the "wxEVT_SHOW" event comes, this event happens just after we set the event handler for this event.


--- Code: ---void CCManager::OnAutocompleteSelect(wxListEvent& event)
{
    event.Skip();
    m_AutocompSelectTimer.Start(AUTOCOMP_SELECT_DELAY, wxTIMER_ONE_SHOT);
    wxObject* evtObj = event.GetEventObject();
    if (!evtObj)
        return;
#ifdef __WXMSW__
    m_pAutocompPopup = static_cast<wxListView*>(evtObj);
#endif // __WXMSW__

    wxWindow* evtWin = static_cast<wxWindow*>(evtObj)->GetParent();
    if (!evtWin)
        return;

    m_DocPos = m_pPopup->GetParent()->ScreenToClient(evtWin->GetScreenPosition());
    m_DocPos.x += evtWin->GetSize().x;
    cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
    wxRect edRect = ed->GetRect();
    if (!m_pPopup->IsShown())
    {
        cbStyledTextCtrl* stc = ed->GetControl();
        int acMaxHeight = stc->AutoCompGetMaxHeight() + 1;
        int textHeight = stc->TextHeight(stc->GetCurrentLine());
        m_DocSize.x = edRect.width * 5 / 12;
        m_DocSize.y = acMaxHeight * textHeight;
        evtWin->Connect(wxEVT_SHOW, wxShowEventHandler(CCManager::OnAutocompleteHide), nullptr, this);
        Manager::Get()->GetLogManager()->DebugLog(F(_T("CCManager::OnAutocompleteSelect connet wxEVT_SHOW event")));
        const int idx = wxDisplay::GetFromWindow(evtWin);
        m_WindowBound = m_DocPos.x + m_DocSize.x;
        if (idx != wxNOT_FOUND)
        {
            const wxPoint& corner = m_pPopup->GetParent()->ScreenToClient(wxDisplay(idx).GetGeometry().GetBottomRight());
            m_DocSize.y = std::max(9 * textHeight,      std::min(m_DocSize.y, corner.y - m_DocPos.y - 2));
            m_DocSize.x = std::max(m_DocSize.y * 2 / 3, std::min(m_DocSize.x, corner.x - m_DocPos.x - 2));
            m_WindowBound = std::min(corner.x - 2, m_WindowBound);
        }
    }
    if ((m_DocPos.x + m_DocSize.x) > m_WindowBound)
        m_DocPos.x -= evtWin->GetSize().x + m_DocSize.x; // show to the left instead
    else
        m_DocSize.x = std::min(m_WindowBound - m_DocPos.x, edRect.width * 5 / 12);
}

--- End code ---
The connection is here

--- Code: ---evtWin->Connect(wxEVT_SHOW, wxShowEventHandler(CCManager::OnAutocompleteHide), nullptr, this);
--- End code ---
But after that, I see wxEVT_SHOW happens, then CCManager::OnAutocompleteHide just cancel the suggestion list.


--- Code: ---// Note: according to documentation, this event is only available under wxMSW, wxGTK, and wxOS2
void CCManager::OnAutocompleteHide(wxShowEvent& event)
{
    event.Skip();
    Manager::Get()->GetLogManager()->DebugLog(F(_T("OnAutocompleteHide show=%d"), event.IsShown()==true? 1:0));
    DoHidePopup();
    wxObject* evtObj = event.GetEventObject();
    if (evtObj)
    {
        static_cast<wxWindow*>(evtObj)->Disconnect(wxEVT_SHOW, wxShowEventHandler(CCManager::OnAutocompleteHide), nullptr, this);
        Manager::Get()->GetLogManager()->DebugLog(F(_T("disconnet wxEVT_SHOW event")));
    }

    if (m_CallTipActive != wxSCI_INVALID_POSITION && !m_AutoLaunchTimer.IsRunning())
        m_CallTipTimer.Start(CALLTIP_REFRESH_DELAY, wxTIMER_ONE_SHOT);
}
--- End code ---

I have added some "DebugLog" to see what happens, but still don't know why wxEVT_SHOW comes when I just hit the "." after the "obj" in my test code.
Any hints?


ollydbg:

--- Code: ---CCManager::OnCompleteCode(): enter
CCManager::OnCompleteCode(): before calling stc->AutoCompShow()
CCManager::OnAutocompleteSelect(): connet wxEVT_SHOW event
CCManager::OnCompleteCode(): after calling stc->AutoCompShow()
CCManager::OnCompleteCode(): before calling stc->AutoCompSelect()
CCManager::OnAutocompleteHide(): wxShowEvent event received, IsShown=0
CCManager::OnAutocompleteSelect(): disconnet wxEVT_SHOW event handler
CCManager::OnCompleteCode(): after calling stc->AutoCompSelect()
CCManager::OnCompleteCode(): exit
--- End code ---
I see some logs, it looks like the wxShowEvent happens inside the CCManager::OnCompleteCode() call, especially in the  stc->AutoCompSelect().

The bug can be reproduced by just press the menu item "Complete Code" after the "obj.".

ollydbg:
Further debugged for a while, I found that:

--- Code: ---[debug]#0  AutoComplete::Cancel (this=0xac43850) at D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\AutoComplete.cxx:209
[debug]D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\AutoComplete.cxx:209:5196:beg:0x1f20c37
[debug]>>>>>>cb_gdb:

At D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\AutoComplete.cxx:209

[debug]> bt 30
[debug]#0  AutoComplete::Cancel (this=0xac43850) at D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\AutoComplete.cxx:209
[debug]#1  0x01f21018 in AutoComplete::Select (this=0xac43850, word=0xa835d30 "aaa1: int") at D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\AutoComplete.cxx:279
[debug]#2  0x01f19b7e in ScintillaBase::WndProc (this=0xac42ad8, iMessage=2108, wParam=0, lParam=176381232) at D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\scintilla\src\ScintillaBase.cxx:806
[debug]#3  0x01e4e6aa in ScintillaWX::WndProc (this=0xac42ad8, iMessage=2108, wParam=0, lParam=176381232) at D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\ScintillaWX.cpp:948
[debug]#4  0x01e37c31 in wxScintilla::SendMsg (this=0xac48380, msg=2108, wp=0, lp=176381232) at D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\wxscintilla.cpp:280
[debug]#5  0x01e3a209 in wxScintilla::AutoCompSelect (this=0xac48380, text=L"aaa1: int") at D:\code\cb\cb_sf_git\trunk\src\sdk\wxscintilla\src\wxscintilla.cpp:1300
[debug]#6  0x01d5849c in CCManager::OnCompleteCode (this=0xabfb110, event=...) at D:\code\cb\cb_sf_git\trunk\src\sdk\ccmanager.cpp:582
[debug]#7  0x01f766c3 in cbEventFunctor<CCManager, CodeBlocksEvent>::Call (this=0xa76a440, event=...) at D:\code\cb\cb_sf_git\trunk\src\include\cbfunctor.h:49
[debug]#8  0x01dd15bd in Manager::ProcessEvent (this=0x57c0348, event=...) at D:\code\cb\cb_sf_git\trunk\src\sdk\manager.cpp:264
[debug]#9  0x004613fa in MainFrame::OnEditCompleteCode (this=0x76301a8, event=...) at D:\code\cb\cb_sf_git\trunk\src\src\main.cpp:3684
[debug]#10 0x68702eb2 in wxAppConsoleBase::HandleEvent(wxEvtHandler*, void (wxEvtHandler::*)(wxEvent&), wxEvent&) const () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#11 0x68703217 in wxAppConsoleBase::CallEventHandler(wxEvtHandler*, wxEventFunctor&, wxEvent&) const () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#12 0x6885bc80 in wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#13 0x6885bd6a in wxEventHashTable::HandleEvent(wxEvent&, wxEvtHandler*) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#14 0x6885c549 in wxEvtHandler::TryHereOnly(wxEvent&) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#15 0x6885bf0c in wxEvtHandler::DoTryChain(wxEvent&) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#16 0x6885c615 in wxEvtHandler::ProcessEvent(wxEvent&) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#17 0x68b24c8a in wxWindowBase::TryAfter(wxEvent&) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#18 0x6885dff2 in wxEvtHandler::SafelyProcessEvent(wxEvent&) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#19 0x68acb860 in wxMenuBase::DoProcessEvent(wxMenuBase*, wxEvent&, wxWindow*) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#20 0x68acb980 in wxMenuBase::SendEvent(int, int) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#21 0x68a72907 in wxFrameBase::ProcessCommand(wxMenuItem*) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#22 0x6898ceea in wxFrame::HandleCommand(unsigned short, unsigned short, HWND__*) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#23 0x6898e275 in wxFrame::MSWWindowProc(unsigned int, unsigned int, long) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#24 0x6893c8b3 in wxWndProc(HWND__*, unsigned int, unsigned int, long)@16 () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#25 0x765a62fa in gapfnScSendMessage () from C:\windows\syswow64\user32.dll
[debug]#26 0x00030570 in ?? ()
[debug]#27 0x765a6d3a in USER32!GetThreadDesktop () from C:\windows\syswow64\user32.dll
[debug]#28 0x6893c840 in wxWindow::SubclassWin(HWND__*) () from D:\code\wxWidgets-3.1.0\lib\gcc_dll\wxmsw310u_gcc_cb.dll
[debug]#29 0x765a77c4 in USER32!CharPrevW () from C:\windows\syswow64\user32.dll
[debug](More stack frames follow...)
[debug]>>>>>>cb_gdb:


--- End code ---

Here, inside the function

--- Code: ---void AutoComplete::Select(const char *word) {
size_t lenWord = strlen(word);
int location = -1;
int start = 0; // lower bound of the api array block to search
int end = lb->Length() - 1; // upper bound of the api array block to search
while ((start <= end) && (location == -1)) { // Binary searching loop
int pivot = (start + end) / 2;
char item[maxItemLen];
lb->GetValue(sortMatrix[pivot], item, maxItemLen);
int cond;
if (ignoreCase)
cond = CompareNCaseInsensitive(word, item, lenWord);
else
cond = strncmp(word, item, lenWord);
if (!cond) {
// Find first match
while (pivot > start) {
lb->GetValue(sortMatrix[pivot-1], item, maxItemLen);
if (ignoreCase)
cond = CompareNCaseInsensitive(word, item, lenWord);
else
cond = strncmp(word, item, lenWord);
if (0 != cond)
break;
--pivot;
}
location = pivot;
if (ignoreCase
&& ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) {
// Check for exact-case match
for (; pivot <= end; pivot++) {
lb->GetValue(sortMatrix[pivot], item, maxItemLen);
if (!strncmp(word, item, lenWord)) {
location = pivot;
break;
}
if (CompareNCaseInsensitive(word, item, lenWord))
break;
}
}
} else if (cond < 0) {
end = pivot - 1;
} else if (cond > 0) {
start = pivot + 1;
}
}
if (location == -1) {
if (autoHide)
Cancel();
else
lb->Select(-1);
} else {
if (autoSort == SC_ORDER_CUSTOM) {
// Check for a logically earlier match
char item[maxItemLen];
for (int i = location + 1; i <= end; ++i) {
lb->GetValue(sortMatrix[i], item, maxItemLen);
if (CompareNCaseInsensitive(word, item, lenWord))
break;
if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item, lenWord))
location = i;
}
}
lb->Select(sortMatrix[location]);
}
}

--- End code ---

Here, it goes to the "Cancel();“ call.

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version