Morten: Please try wx3.0 or wx-master branch, if possible. The reported problem is with wx3.0.2.
Yes, on wx3.0.2 it shows the effect. However, we should not seriously try to fix it in trunk. Instead, we should focus and fix the scintilla branch. I am still trying to get it working but so far I didn't have enough time to finish. We lack behind many versions already and there have been massive fundamental changes in the architecture of scintilla. So give it a try, if you like:
https://svn.code.sf.net/p/codeblocks/code/branches/scintilla_3_6_x
A patch to fix the build error:
src/CodeBlocks_wx30.cbp | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/src/CodeBlocks_wx30.cbp b/src/CodeBlocks_wx30.cbp
index 263249e..d98b603 100644
--- a/src/CodeBlocks_wx30.cbp
+++ b/src/CodeBlocks_wx30.cbp
@@ -3416,6 +3416,9 @@
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexBasic.cxx">
<Option target="scintilla" />
</Unit>
+ <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexBatch.cxx">
+ <Option target="scintilla" />
+ </Unit>
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexBibTeX.cxx">
<Option target="scintilla" />
</Unit>
@@ -3461,6 +3464,9 @@
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexDMIS.cxx">
<Option target="scintilla" />
</Unit>
+ <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexDiff.cxx">
+ <Option target="scintilla" />
+ </Unit>
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexECL.cxx">
<Option target="scintilla" />
</Unit>
@@ -3473,6 +3479,9 @@
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexErlang.cxx">
<Option target="scintilla" />
</Unit>
+ <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexErrorList.cxx">
+ <Option target="scintilla" />
+ </Unit>
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexFlagship.cxx">
<Option target="scintilla" />
</Unit>
@@ -3530,6 +3539,9 @@
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexMagik.cxx">
<Option target="scintilla" />
</Unit>
+ <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexMake.cxx">
+ <Option target="scintilla" />
+ </Unit>
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexMarkdown.cxx">
<Option target="scintilla" />
</Unit>
@@ -3551,13 +3563,13 @@
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexNsis.cxx">
<Option target="scintilla" />
</Unit>
- <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexOScript.cxx">
+ <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexNull.cxx">
<Option target="scintilla" />
</Unit>
- <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexOpal.cxx">
+ <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexOScript.cxx">
<Option target="scintilla" />
</Unit>
- <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexOthers.cxx">
+ <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexOpal.cxx">
<Option target="scintilla" />
</Unit>
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexPB.cxx">
@@ -3590,6 +3602,9 @@
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexProgress.cxx">
<Option target="scintilla" />
</Unit>
+ <Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexProps.cxx">
+ <Option target="scintilla" />
+ </Unit>
<Unit filename="sdk/wxscintilla/src/scintilla/lexers/LexPython.cxx">
<Option target="scintilla" />
</Unit>
When debug the scintilla branch with wx 3.02 under windows, I noticed that when an editor opened by the statement:
m_pControl->InsertText(0, enc.GetWxStr());
case SCI_INSERTTEXT: {
if (lParam == 0)
return 0;
int insertPos = static_cast<int>(wParam);
if (static_cast<int>(wParam) == -1)
insertPos = CurrentPosition();
int newCurrent = CurrentPosition();
char *sz = CharPtrFromSPtr(lParam);
const int lengthInserted = pdoc->InsertString(insertPos, sz, istrlen(sz));
if (newCurrent > insertPos)
newCurrent += lengthInserted;
SetEmptySelection(newCurrent);
return 0;
}
And I see that the null terminated string is needed, but when debugging, I see we pass a string with out the null at the end.
This gives the screen shot:
(http://i683.photobucket.com/albums/vv194/ollydbg_cb/2015-12-23%2023%2015%2029_zpsp0itycke.png)
void UTF8FromUTF16(const wchar_t *uptr, unsigned int tlen, char *putf, unsigned int len) {
unsigned int k = 0;
for (unsigned int i = 0; i < tlen && uptr[i];) {
unsigned int uch = uptr[i];
if (uch < 0x80) {
putf[k++] = static_cast<char>(uch);
} else if (uch < 0x800) {
putf[k++] = static_cast<char>(0xC0 | (uch >> 6));
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
} else if ((uch >= SURROGATE_LEAD_FIRST) &&
(uch <= SURROGATE_TRAIL_LAST)) {
// Half a surrogate pair
i++;
unsigned int xch = 0x10000 + ((uch & 0x3ff) << 10) + (uptr[i] & 0x3ff);
putf[k++] = static_cast<char>(0xF0 | (xch >> 18));
putf[k++] = static_cast<char>(0x80 | ((xch >> 12) & 0x3f));
putf[k++] = static_cast<char>(0x80 | ((xch >> 6) & 0x3f));
putf[k++] = static_cast<char>(0x80 | (xch & 0x3f));
} else {
putf[k++] = static_cast<char>(0xE0 | (uch >> 12));
putf[k++] = static_cast<char>(0x80 | ((uch >> 6) & 0x3f));
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
}
i++;
}
if (k < len)
putf[k] = '\0';
}
Now, the last two line, I have k == len, and I see there is NO chances to set the null terminator.
void UTF8FromUTF16(const wchar_t *uptr, unsigned int tlen, char *putf, unsigned int len) {
unsigned int k = 0;
for (unsigned int i = 0; i < tlen && uptr[i];) {
unsigned int uch = uptr[i];
if (uch < 0x80) {
putf[k++] = static_cast<char>(uch);
} else if (uch < 0x800) {
putf[k++] = static_cast<char>(0xC0 | (uch >> 6));
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
} else if ((uch >= SURROGATE_LEAD_FIRST) &&
(uch <= SURROGATE_TRAIL_LAST)) {
// Half a surrogate pair
i++;
unsigned int xch = 0x10000 + ((uch & 0x3ff) << 10) + (uptr[i] & 0x3ff);
putf[k++] = static_cast<char>(0xF0 | (xch >> 18));
putf[k++] = static_cast<char>(0x80 | ((xch >> 12) & 0x3f));
putf[k++] = static_cast<char>(0x80 | ((xch >> 6) & 0x3f));
putf[k++] = static_cast<char>(0x80 | (xch & 0x3f));
} else {
putf[k++] = static_cast<char>(0xE0 | (uch >> 12));
putf[k++] = static_cast<char>(0x80 | ((uch >> 6) & 0x3f));
putf[k++] = static_cast<char>(0x80 | (uch & 0x3f));
}
i++;
}
if (k < len)
putf[k] = '\0';
}
Now, the last two line, I have k == len, and I see there is NO chances to set the null terminator.
OK, the following patch should fix the issue:
src/sdk/wxscintilla/src/scintilla/src/UniConversion.cxx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/sdk/wxscintilla/src/scintilla/src/UniConversion.cxx b/src/sdk/wxscintilla/src/scintilla/src/UniConversion.cxx
index c12ca34..e987963 100644
--- a/src/sdk/wxscintilla/src/scintilla/src/UniConversion.cxx
+++ b/src/sdk/wxscintilla/src/scintilla/src/UniConversion.cxx
@@ -68,7 +68,7 @@ void UTF8FromUTF16(const wchar_t *uptr, unsigned int tlen, char *putf, unsigned
}
i++;
}
- if (k < len)
+ if (k <= len)
putf[k] = '\0';
}
This not only fix the issue about the extra bytes in the content of the cbEditor, it also fix the wrong line number margin width issue. Also, before using this patch, the font is totally wrong, and with this patch, the font in the editor is OK now.
Debugged for a while, I found that, when I click on a brace(if there are some braces already highlighted)
I get to those code:
void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
CheckForChangeOutsidePaint(Range(braces[0]));
CheckForChangeOutsidePaint(Range(pos0));
braces[0] = pos0;
}
if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
CheckForChangeOutsidePaint(Range(braces[1]));
CheckForChangeOutsidePaint(Range(pos1));
braces[1] = pos1;
}
bracesMatchStyle = matchStyle;
if (paintState == notPainting) {
Redraw();
}
}
}
This function is called inside the function call "Paint(surfaceWindow, rcPaint);" inside the below function.
void ScintillaWX::DoPaint(wxDC* dc, wxRect rect) {
paintState = painting;
AutoSurface surfaceWindow(dc, this);
if (surfaceWindow) {
rcPaint = PRectangleFromwxRect(rect);
PRectangle rcClient = GetClientRectangle();
paintingAllText = rcPaint.Contains(rcClient);
ClipChildren(*dc, rcPaint);
Paint(surfaceWindow, rcPaint);
surfaceWindow->Release();
}
if (paintState == paintAbandoned) {
// Painting area was insufficient to cover new styling or brace
// highlight positions. So trigger a new paint event that will
// repaint the whole window.
sci->Refresh(false);
#if defined(__WXOSX__)
// On Mac we also need to finish the current paint to make sure that
// everything is on the screen that needs to be there between now and
// when the next paint event arrives.
FullPaintDC(dc);
#endif
}
paintState = notPainting;
}
Then, we will get into the condition that satisfy this condition "if (!PaintContains(rcRange))", so that "paintAbandonedByStyling = true;" is reached.
void Editor::CheckForChangeOutsidePaint(Range r) {
if (paintState == painting && !paintingAllText) {
//Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
if (!r.Valid())
return;
PRectangle rcRange = RectangleFromRange(r, 0);
PRectangle rcText = GetTextRectangle();
if (rcRange.top < rcText.top) {
rcRange.top = rcText.top;
}
if (rcRange.bottom > rcText.bottom) {
rcRange.bottom = rcText.bottom;
}
if (!PaintContains(rcRange)) {
AbandonPaint();
paintAbandonedByStyling = true;
}
}
}
Back to the function "void ScintillaWX::DoPaint(wxDC* dc, wxRect rect)", you will see the Refresh() call is reached.
if (paintState == paintAbandoned) {
// Painting area was insufficient to cover new styling or brace
// highlight positions. So trigger a new paint event that will
// repaint the whole window.
sci->Refresh(false);
Now, you get a repaint:
void wxScintilla::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
#ifdef __WXGTK__
wxBufferedPaintDC dc(this);
#else
wxPaintDC dc(this);
#endif
m_swx->DoPaint(&dc, GetUpdateRegion().GetBox());
}
But here comes the bug!
I see that "GetUpdateRegion().GetBox()" only gives the area around the current line. This not cover the old brace highlight, so that the old brace highlight is not removed. Also, if you click on the "{", while the associated "}" is on the other line(which means the "}" is not in the area of the "GetUpdateRegion().GetBox()"), so the "}" is not highlighted.
What's wrong with the "GetUpdateRegion().GetBox()", It should at least be a rectangle area which covers the current braces and the old braces.
I just tested the buildin stc control inside the wx 3.0.2. It does not show such issue.
Here are the steps:
1, build the sample/stc project. (I use Tim's wx c::b project, see: stahta01/cb_projects_for_wxWidgets ยท GitHub (https://github.com/stahta01/cb_projects_for_wxWidgets), also, you can build the stc project with traditional makefile)
2, make some changes to edit.cpp:
void Edit::OnUpdate(wxStyledTextEvent &WXUNUSED(event))
{
int min = GetCurrentPos ();
int max = BraceMatch (min);
if (max > (min+1)) {
BraceHighlight (min, max);
}else{
BraceBadLight (min);
}
}
And add one prototype:
void OnUpdate (wxStyledTextEvent &event);
Also, one entry to the message map:
EVT_STC_UPDATEUI(wxID_ANY, Edit::OnUpdate)
3, Here is the test code:
EDIT:
wx 3.0.2's buildin scintilla version is 3.21, which is quite old.
Also, the above brace high light only works you put the cursor before the beginning brace.
OK, I found this issue is really strange, I just test the wxScintilla in our C::B's svn repo. We have a cctest project, which use this wxScintilla. Here is the patch to enable the brace highlight feature in cctest's editor:
ff0cf37bef56645539ebf000d2ddf7d98fcf2dac
src/plugins/codecompletion/cctest/cctest_frame.cpp | 14 ++++++++++++++
src/plugins/codecompletion/cctest/cctest_frame.h | 1 +
2 files changed, 15 insertions(+)
diff --git a/src/plugins/codecompletion/cctest/cctest_frame.cpp b/src/plugins/codecompletion/cctest/cctest_frame.cpp
index e8a0626..cbbcae2 100644
--- a/src/plugins/codecompletion/cctest/cctest_frame.cpp
+++ b/src/plugins/codecompletion/cctest/cctest_frame.cpp
@@ -474,6 +474,9 @@ void CCTestFrame::InitControl()
Connect(m_Control->GetId(), -1, wxEVT_SCI_MARGINCLICK,
(wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
&CCTestFrame::OnMarginClick);
+ Connect(m_Control->GetId(), -1, wxEVT_SCI_UPDATEUI,
+ (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
+ &CCTestFrame::OnUpdate);
}
void CCTestFrame::SetMarkerStyle(int marker, int markerType, wxColor fore, wxColor back)
@@ -590,6 +593,17 @@ void CCTestFrame::OnMarginClick(wxScintillaEvent& event)
}
}
+void CCTestFrame::OnUpdate(wxScintillaEvent &WXUNUSED(event))
+{
+ int min = m_Control->GetCurrentPos ();
+ int max = m_Control->BraceMatch (min);
+ if (max > (min+1)) {
+ m_Control->BraceHighlight (min, max);
+ }else{
+ m_Control->BraceBadLight (min);
+ }
+}
+
void CCTestFrame::OnFindDialog(wxFindDialogEvent& event)
{
wxEventType type = event.GetEventType();
diff --git a/src/plugins/codecompletion/cctest/cctest_frame.h b/src/plugins/codecompletion/cctest/cctest_frame.h
index d41538f..6f86ebe 100644
--- a/src/plugins/codecompletion/cctest/cctest_frame.h
+++ b/src/plugins/codecompletion/cctest/cctest_frame.h
@@ -73,6 +73,7 @@ private:
void OnFindDialog(wxFindDialogEvent& event);
void OnCCLogger(wxCommandEvent& event);
void OnCCAddToken(wxCommandEvent& event);
+ void OnUpdate(wxScintillaEvent &event);
//(*Declarations(CCTestFrame)
While, the result is: It works just fine!
So, here comes the question: maybe the issue is NOT inside the wxScintilla, maybe our C::B core(SDK) has some code which destroy the feature.
OK, I did some test. I see that if I comment the line:
NotifyPlugins(cbEVT_EDITOR_UPDATE_UI);
inside the function: void cbEditor::OnEditorUpdateUI(wxScintillaEvent& event), then the brace highlight works just fine in C::B.
So, what is the client of this cbEVT_EDITOR_UPDATE_UI? In my tests, I have disable all the plugins, so it looks like the only client which use cbEVT_EDITOR_UPDATE_UI is inside the src target, which locates below:
void MainFrame::OnEditorUpdateUI(CodeBlocksEvent& event)
{
if (Manager::IsAppShuttingDown())
{
event.Skip();
return;
}
if (Manager::Get()->GetEditorManager() && event.GetEditor() == Manager::Get()->GetEditorManager()->GetActiveEditor())
DoUpdateStatusBar();
event.Skip();
}
Does DoUpdateStatusBar cause the issue?
EDIT: I can confirm that DoUpdateStatusBar does cause this issue. If I comment out the line:
, I see brace high light works fine.
If I comment out the two lines:
msg.Printf(_("Line %d, Column %d"), ed->GetControl()->GetCurrentLine() + 1, ed->GetControl()->GetColumn(pos) + 1);
SetStatusText(msg, panel++);
From the function: void MainFrame::DoUpdateStatusBar(), then the brace high light works fine!
I just did more test:
1, I try to minimize the issue, so I add such code in our cctest w30 project.
Here is the modified function:
void CCTestFrame::OnUpdate(wxScintillaEvent &WXUNUSED(event))
{
int min = m_Control->GetCurrentPos ();
int max = m_Control->BraceMatch (min);
if (max > (min+1)) {
m_Control->BraceHighlight (min, max);
int pos = m_Control->GetCurrentLine();
wxString msg;
msg.Printf(_("Line %d, Column %d"), m_Control->GetCurrentLine() + 1, m_Control->GetColumn(pos) + 1);
SetStatusText(msg, 0);
}else{
m_Control->BraceBadLight (min);
}
}
You see here, I have both set the BraceHighlight and the Status Bar.
Now, the issue happens.
2, I did a quite similar test on the wx 3.0.2's build in stc sample:
Add a status bar in the frame's constructor(a member variable wxStatusBar* m_StatuBar; is need also)
m_StatuBar = new wxStatusBar(this, wxID_ANY, 0, _T("wxID_ANY"));
int __wxStatusBarWidths_1[1] = { -10 };
int __wxStatusBarStyles_1[1] = { wxSB_NORMAL };
m_StatuBar->SetFieldsCount(1,__wxStatusBarWidths_1);
m_StatuBar->SetStatusStyles(1,__wxStatusBarStyles_1);
SetStatusBar(m_StatuBar);
Then, bind the event to the frame, not the Edit control.
void AppFrame::OnUpdate(wxStyledTextEvent &WXUNUSED(event))
{
int min = m_edit->GetCurrentPos ();
int max = m_edit->BraceMatch (min);
if (max > (min+1)) {
m_edit->BraceHighlight (min, max);
int pos = m_edit->GetCurrentLine();
wxString msg;
msg.Printf(_("Line %d, Column %d"), m_edit->GetCurrentLine() + 1, m_edit->GetColumn(pos) + 1);
SetStatusText(msg, 0);
}else{
m_edit->BraceBadLight (min);
}
}
The macro is like below:
// handle the update event
EVT_STC_UPDATEUI(wxID_ANY, AppFrame::OnUpdate)
Note, that you need to comment out the EVT_STC_UPDATEUI macro inside the edit.cpp.
The result is: It works OK without the issue.
EDIT: I see that this issue also happens!!
I really don't know why SetStatusText() call cause such issue. Is it caused by the local variable msg?
EDIT: Now, I see all the above cases will cause the issue!
The following patch fix the issue!
src/src/main.cpp | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/src/main.cpp b/src/src/main.cpp
index d94083d..8b6f848 100644
--- a/src/src/main.cpp
+++ b/src/src/main.cpp
@@ -4240,7 +4240,15 @@ void MainFrame::OnEditorUpdateUI(CodeBlocksEvent& event)
}
if (Manager::Get()->GetEditorManager() && event.GetEditor() == Manager::Get()->GetEditorManager()->GetActiveEditor())
- DoUpdateStatusBar();
+ {
+ #if wxCHECK_VERSION(2,9,5)
+ // try to avoid an issue when set status bar inside the editor update ui event breaks
+ // the brace high light, see: http://forums.codeblocks.org/index.php/topic,20795.0.html
+ CallAfter(&MainFrame::DoUpdateStatusBar);
+ #else
+ DoUpdateStatusBar();
+ #endif
+ }
event.Skip();
}