Author Topic: Splitting debugger in two - specific debugger and common GUI  (Read 431499 times)

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9694
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #480 on: August 10, 2011, 09:55:50 pm »
Please test it. I'm using it every day on my linux, but have done very little testing on windows, so feedback is welcome.
Would you mind to commit for testing? This would make things a little easier.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: https://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: https://wiki.codeblocks.org/index.php?title=FAQ

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5915
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #481 on: August 11, 2011, 04:18:08 am »
The patch is only partially applied in the debugger branch.
I just update to rev 7362, but found that it's hard to apply the patch. So, I revert back to rev 7342, and apply the patch. :D

@obF:
cbEVT_EDITOR_TOOLTIP is sent from cbEditor to notify all the plugins, and which is cause by receiving the DWellStart event from scintilla control.

Code
    Connect( m_ID,  -1, wxEVT_SCI_DWELLSTART,
                  (wxObjectEventFunction) (wxEventFunction) (wxScintillaEventFunction)
                  &cbEditor::OnEditorDwellStart );

and

Code
void cbEditor::OnEditorDwellStart(wxScintillaEvent& event)
{
    if (!wxTheApp->IsActive())
        return;

    cbStyledTextCtrl* control = GetControl();
    if (!control)
        return;

    wxRect screenRect = control->GetScreenRect();
    wxPoint ptEvent(event.GetX(), event.GetY());
    ptEvent = control->ClientToScreen(ptEvent);
    wxPoint ptScreen = wxGetMousePosition();
    wxPoint ptClient = control->ScreenToClient(ptScreen);

    double distance = sqrt(  (ptScreen.x - ptEvent.x) * (ptScreen.x - ptEvent.x)
                           + (ptScreen.y - ptEvent.y) * (ptScreen.y - ptEvent.y) );
    if (!screenRect.Contains(ptScreen) || distance > 10)
        return;

    int pos = control->PositionFromPoint(ptClient);
    int style = control->GetStyleAt(pos);
    NotifyPlugins(cbEVT_EDITOR_TOOLTIP, style, wxEmptyString, ptClient.x, ptClient.y);
    wxScintillaEvent newEvent(event);
    newEvent.SetX(ptClient.x);
    newEvent.SetY(ptClient.y);
    OnScintillaEvent(event);
}

and
Code
void wxScintilla::NotifyParent (SCNotification* _scn)
{
    SCNotification& scn = *_scn;
    wxScintillaEvent evt (0, GetId());

    evt.SetEventObject(this);
    evt.SetPosition(scn.position);
    evt.SetKey(scn.ch);
    evt.SetModifiers(scn.modifiers);

    switch (scn.nmhdr.code) {
    case SCN_STYLENEEDED:
        evt.SetEventType (wxEVT_SCI_STYLENEEDED);
        break;
    .......
    .......
    case SCN_DWELLSTART:
        evt.SetEventType (wxEVT_SCI_DWELLSTART);
        evt.SetX(scn.x);
        evt.SetY(scn.y);
        break;

the logic of sending SCN_DWELLSTART is much simple. in scintilla control, there is a timer, when the control received the MouseMove event, it will always restart the timer, if for about 500ms there is not MouseMove event happens, then the timer event handler will  be fired, and send a SCN_DWELLSTART event.
Any MouseMove or keypress will let restart the timer and send a SCN_DWELLEND event.

Applying your patch, I see that both codecompletion plugin and debugger plugin will have a handler to response the cbEVT_EDITOR_TOOLTIP event from SDK, I found such code in debugger's handler:

Code
void cbDebuggerPlugin::ProcessValueTooltip(CodeBlocksEvent& event)
{
    event.Skip();
    if (cbDebuggerCommonConfig::GetFlag(cbDebuggerCommonConfig::RequireCtrlForTooltips))
    {
        if (!wxGetKeyState(WXK_CONTROL))
            return;
    }

    if (!ShowValueTooltip(event.GetInt()))
        return;

    EditorBase* base = event.GetEditor();
    cbEditor* ed = base && base->IsBuiltinEditor() ? static_cast<cbEditor*>(base) : 0;
    if (!ed)
        return;

    if (ed->IsContextMenuOpened())
        return;

    // get rid of other calltips (if any) [for example the code completion one, at this time we
    // want the debugger value call/tool-tip to win and be shown]
    if (ed->GetControl()->CallTipActive())
        ed->GetControl()->CallTipCancel();

    wxPoint pt;
    pt.x = event.GetX();
    pt.y = event.GetY();

    const wxString &token = GetEditorWordAtCaret(&pt);
    if (!token.empty())
    {
        pt = ed->GetControl()->ClientToScreen(pt);
        OnValueTooltip(token, wxRect(pt.x - 5, pt.y, 10, 10));
    }
}
This has the assumption that CC's handler is running before the debugger's handler. In-fact, there is no grantee which tip handler will run before other one. if CC's handler runs later, it will destroy the debugger's tip. This is a race condition. :D we have discussed before.

also, this code:
Code
    if (cbDebuggerCommonConfig::GetFlag(cbDebuggerCommonConfig::RequireCtrlForTooltips))
    {
        if (!wxGetKeyState(WXK_CONTROL))
            return;
    }
Does not works under Windows for sure. I have exam this condition before. Under windows, if you hold the control key, then the timer in scintilla control will notice that your have press a key, and do a restart always, and the time handler never fired. (I'm not sure how the scintilla control was implemented under Linux), even though the SCN_DWELLSTART is already send, when detecting the ctrl key, it will quickly send a SCN_DWELLEND event to destroy the tip.

The other issue is related in my post:
DWELL Windows Question
I can filter the ctrl key, so the sci control send SCN_DWELLSTART event does not consider the ctrl condition. the client has the duty to check whether show or disable the tip depend on the ctrl key condition. After your tip window is shown, if you still hold on the ctrl key. the tip window will received the key press event, and destroy the tip. at this condition, you need to filter the ctrl key event in the tip window too.






If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #482 on: August 11, 2011, 08:39:39 am »
The patch is only partially applied in the debugger branch.
I just update to rev 7362, but found that it's hard to apply the patch. So, I revert back to rev 7342, and apply the patch. :D
Yes, sorry for that but my batteries hit the low end and I had to go to bed :(

This has the assumption that CC's handler is running before the debugger's handler. In-fact, there is no grantee which tip handler will run before other one. if CC's handler runs later, it will destroy the debugger's tip. This is a race condition. :D we have discussed before.
Do you know a better way? I don't, so this is the best we can do at the moment. And it works.
Some day I could rewrite the whole systems, so both tooltips could be visible.

also, this code:
Code
    if (cbDebuggerCommonConfig::GetFlag(cbDebuggerCommonConfig::RequireCtrlForTooltips))
    {
        if (!wxGetKeyState(WXK_CONTROL))
            return;
    }
Does not works under Windows for sure. I have exam this condition before. Under windows, if you hold the control key, then the timer in scintilla control will notice that your have press a key, and do a restart always, and the time handler never fired. (I'm not sure how the scintilla control was implemented under Linux), even though the SCN_DWELLSTART is already send, when detecting the ctrl key, it will quickly send a SCN_DWELLEND event to destroy the tip.

The other issue is related in my post:
DWELL Windows Question
I can filter the ctrl key, so the sci control send SCN_DWELLSTART event does not consider the ctrl condition. the client has the duty to check whether show or disable the tip depend on the ctrl key condition. After your tip window is shown, if you still hold on the ctrl key. the tip window will received the key press event, and destroy the tip. at this condition, you need to filter the ctrl key event in the tip window too.
I'm not sure I understand, can you provide a patch (after I commit everything)?




(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5915
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #483 on: August 11, 2011, 08:53:10 am »
The patch is only partially applied in the debugger branch.
I just update to rev 7362, but found that it's hard to apply the patch. So, I revert back to rev 7342, and apply the patch. :D
Yes, sorry for that but my batteries hit the low end and I had to go to bed :(
:D

Quote
Do you know a better way? I don't, so this is the best we can do at the moment. And it works.
Some day I could rewrite the whole systems, so both tooltips could be visible.
We have a discussion here:
show debugger tip under curser when ctrl key is pressed
and race condition explanation by jens
also you said it works on Linux

Quote
I'm not sure I understand, can you provide a patch (after I commit everything)?

The patch is already here, but I think that the way in codelite is much better ( it emulate an event, also it handle the race condition ).




If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #484 on: August 11, 2011, 09:57:01 am »
OK, I'll see what can be done tonight.
Can you show me the exact revisions of the changes in CodeLight?

Everything is committed now. Happy testing.

btw. DBG tooltip almost always wins (it is shown later), because there is some delay evaluating the variable.  8)
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5915
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #485 on: August 11, 2011, 10:03:53 am »
OK, I'll see what can be done tonight.
Can you show me the exact revisions of the changes in CodeLight?
It's also in the same post: codelite's way to emulate a event when ctrl pressed.
Codelite has the code repository on sourceforge:SourceForge.net: CodeLite: SCM

Quote
Everything is committed now. Happy testing.
btw. DBG tooltip almost always wins (it is shown later), because there is some delay evaluating the variable.  8)
Thanks and that's great!
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5915
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #486 on: August 11, 2011, 03:36:58 pm »
by the way, codelite has a tip improvement, see:

Quote
Revision: 4686
Author: eranif
Date: 2:39:01, 2011 1 3
Message:
- Debugger: when the option to show the debugger tip only if CTRL key is down is ON, the tip will now be shown immediately without the need to "move" the mouse
----
Modified : /trunk/LiteEditor/cl_editor.cpp
Modified : /trunk/LiteEditor/context_cpp.cpp

In this rev, an emulated event is added.


If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #487 on: August 11, 2011, 04:25:18 pm »
I'll look at it.... thanks
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5915
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #488 on: August 11, 2011, 04:37:35 pm »
One change in the scintilla editor should be like below:
Code
Index: E:/code/cb/cb_debugger_branch/src/sdk/wxscintilla/src/scintilla/src/Editor.cxx
===================================================================
--- E:/code/cb/cb_debugger_branch/src/sdk/wxscintilla/src/scintilla/src/Editor.cxx (revision 7366)
+++ E:/code/cb/cb_debugger_branch/src/sdk/wxscintilla/src/scintilla/src/Editor.cxx (working copy)
@@ -5580,7 +5580,9 @@
 }
 
 int Editor::KeyDownWithModifiers(int key, int modifiers, bool *consumed) {
- DwellEnd(false);
+    //any key other than ctrl will cause the dwell end
+    if(modifiers!=SCI_CTRL)
+        DwellEnd(false);
  int msg = kmap.Find(key, modifiers);
  if (msg) {
  if (consumed)

Compare with my last patch: my last patch
it seem you did not use "GDBTipWindowView" or "GDBTipWindow" to show the tip?

as you said:
Quote
- Added implementation of the tooltip using wxPropertyGrid
, does this tip only used for watch dialog?

I just exam the code:
Code
void cbDebuggerPlugin::ProcessValueTooltip(CodeBlocksEvent& event)
{
    event.Skip();
    if (cbDebuggerCommonConfig::GetFlag(cbDebuggerCommonConfig::RequireCtrlForTooltips))
    {
        if (!wxGetKeyState(WXK_CONTROL))
            return;
    }

    if (!ShowValueTooltip(event.GetInt()))
        return;

    EditorBase* base = event.GetEditor();
    cbEditor* ed = base && base->IsBuiltinEditor() ? static_cast<cbEditor*>(base) : 0;
    if (!ed)
        return;

    if (ed->IsContextMenuOpened())
        return;

    // get rid of other calltips (if any) [for example the code completion one, at this time we
    // want the debugger value call/tool-tip to win and be shown]
    if (ed->GetControl()->CallTipActive())
        ed->GetControl()->CallTipCancel();

    wxPoint pt;
    pt.x = event.GetX();
    pt.y = event.GetY();

    const wxString &token = GetEditorWordAtCaret(&pt);
    if (!token.empty())
    {
        pt = ed->GetControl()->ClientToScreen(pt);
        OnValueTooltip(token, wxRect(pt.x - 5, pt.y, 10, 10));
    }
}
So, where did you actually show the debugger's tip window? In the function
Code
OnValueTooltip(token, wxRect(pt.x - 5, pt.y, 10, 10));
??
I can't see any code snippet to show the tip window. :D
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #489 on: August 11, 2011, 05:07:17 pm »
Compare with my last patch: my last patch
it seem you did not use "GDBTipWindowView" or "GDBTipWindow" to show the tip?
No, I don't :)
See the ValueTooltip class.

as you said:
Quote
- Added implementation of the tooltip using wxPropertyGrid
, does this tip only used for watch dialog?
No, it is not used for the watches, but the value tooltips, set the ValueTooltip class...
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline Jenna

  • Administrator
  • Lives here!
  • *****
  • Posts: 7255
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #490 on: August 11, 2011, 11:05:01 pm »
One annoying thing I found:
if "build to ensure, that project is up to date" is checked, the build-process can not be interrupted if it has started.
In trunk this is still possible.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #491 on: August 11, 2011, 11:07:39 pm »
I know, I have it in the to-do.

This http://smrt.is-a-geek.org/codeblocks/TODO is the full to-do if someone is interested :)
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5915
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #492 on: August 12, 2011, 03:37:33 am »
Compare with my last patch: my last patch
it seem you did not use "GDBTipWindowView" or "GDBTipWindow" to show the tip?
No, I don't :)
See the ValueTooltip class.
Thanks, I found it, it was in parsing the gdb command output, here:
Code
/**
  * Command to display a tooltip about a variables value.
  */
class GdbCmd_TooltipEvaluation : public DebuggerCmd
{
        wxRect m_WinRect;
        wxString m_What;
        wxString m_Type;
        wxString m_Address;
        wxString m_ParseFunc;
    public:
        /** @param what The variable to evaluate.
            @param win A pointer to the tip window pointer.
            @param tiprect The tip window's rect.
        */
        GdbCmd_TooltipEvaluation(DebuggerDriver* driver, const wxString& what, const wxRect& tiprect, const wxString& w_type = wxEmptyString, const wxString& address = wxEmptyString)
            : DebuggerCmd(driver),
            m_WinRect(tiprect),
            m_What(what),
            m_Type(w_type),
            m_Address(address)
        {
            m_Type.Trim(true);
            m_Type.Trim(false);
            m_Cmd = static_cast<GDB_driver*>(m_pDriver)->GetScriptedTypeCommand(w_type, m_ParseFunc);
            if (m_Cmd.IsEmpty())
            {
                // if it's a pointer, automatically dereference it
                if (w_type.Length() > 2 && // at least 2 chars
                    w_type.Last() == _T('*') && // last is *
                    w_type.GetChar(w_type.Length() - 2) != _T('*') && // second last is not * (i.e. doesn't end with **)
                    !w_type.Contains(_T("char "))) // not char* (special case)
                {
                    m_What = wxT("*") + m_What;
                }

                m_Cmd << wxT("output ");
                m_Cmd << m_What;
            }
            else
            {
                try
                {
                    SqPlus::SquirrelFunction<wxString&> f(cbU2C(m_Cmd));
                    m_Cmd = f(w_type, what, 0, 0);
                }
                catch (SquirrelError e)
                {
                    m_Cmd = cbC2U(e.desc);
                    m_pDriver->DebugLog(_T("Script exception: ") + m_Cmd);
                }
            }
        }
        void ParseOutput(const wxString& output)
        {
            wxString contents;
            if (output.StartsWith(_T("No symbol ")) || output.StartsWith(_T("Attempt to ")))
                contents = output;
            else
            {
                if (!m_ParseFunc.IsEmpty())
                {
                    try
                    {
                        SqPlus::SquirrelFunction<wxString&> f(cbU2C(m_ParseFunc));
                        contents << f(output, 0);
                    }
                    catch (SquirrelError e)
                    {
                        contents << cbC2U(e.desc);
                        m_pDriver->DebugLog(_T("Script exception: ") + contents);
                    }
                }
                else
                {
                    contents << output;
                    // the following breaks the text when it *is* a hex number
//                    if (reGenericHexAddress.Matches(output))
//                    {
//                        contents.Replace(reGenericHexAddress.GetMatch(output, 1), _T(""));
//                        contents.Trim(false);
//                    }
                }
            }
            contents.Trim(true);
            contents.Trim(false);

            GDBWatch::Pointer watch(new GDBWatch(m_What));
            watch->SetType(m_Type);

            ParseGDBWatchValue(*watch, contents);

            if (Manager::Get()->GetDebuggerManager()->ShowValueTooltip(watch, m_WinRect))
            {
                watch->SetForTooltip(true);
                m_pDriver->GetDebugger()->AddWatchNoUpdate(watch);
            }
        }
};

I know, I have it in the to-do.
This http://smrt.is-a-geek.org/codeblocks/TODO is the full to-do if someone is interested :)
too many todos.
about the python pretty printer, the latest cvs version of GDB has supply some command like:
"info pretty-printer" to show the installed pretty printers.
"enable/disable pretty-printer" to enable/disable this feature.
These feature can be added when you have some gdb's own pretty-printer utilities scripts in share/gdb folder (I only tested under MinGW).
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline ollydbg

  • Developer
  • Lives here!
  • *****
  • Posts: 5915
  • OpenCV and Robotics
    • Chinese OpenCV forum moderator
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #493 on: August 12, 2011, 08:59:56 am »
a test patch(based on rev 7366 debugger branch) to enable this feature(emulate a message when ctrl pressed when debugging)
need for testing :D
« Last Edit: August 12, 2011, 09:02:36 am by ollydbg »
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 13413
    • Travis build status
Re: Splitting debugger in two - specific debugger and common GUI
« Reply #494 on: August 12, 2011, 09:27:22 am »
too many todos.
I'm adding more items, then removing  8)

a test patch(based on rev 7366 debugger branch) to enable this feature(emulate a message when ctrl pressed when debugging)
need for testing :D
I'll test it on linux...
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]