diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 43ad3133db..ad85396ce7 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -262,6 +262,7 @@ Application Debugger : # user_interface/gui/team_window BreakConditionConfigWindow.cpp + BreakpointEditWindow.cpp BreakpointListView.cpp BreakpointsView.cpp ConsoleOutputView.cpp diff --git a/src/apps/debugger/MessageCodes.h b/src/apps/debugger/MessageCodes.h index 42d99667f0..fdf07db923 100644 --- a/src/apps/debugger/MessageCodes.h +++ b/src/apps/debugger/MessageCodes.h @@ -18,6 +18,8 @@ enum { MSG_CLEAR_BREAKPOINT = 'cbrk', MSG_ENABLE_BREAKPOINT = 'ebrk', MSG_DISABLE_BREAKPOINT = 'dbrk', + MSG_SET_BREAKPOINT_CONDITION = 'sbpc', + MSG_CLEAR_BREAKPOINT_CONDITION = 'cbpc', MSG_SET_WATCHPOINT = 'swpt', MSG_CLEAR_WATCHPOINT = 'cwpt', MSG_ENABLE_WATCHPOINT = 'ewpt', @@ -61,6 +63,8 @@ enum { MSG_TEAMS_WINDOW_CLOSED = 'tswc', MSG_SHOW_BREAK_CONDITION_CONFIG_WINDOW = 'sbcc', MSG_BREAK_CONDITION_CONFIG_WINDOW_CLOSED = 'bccw', + MSG_SHOW_BREAKPOINT_EDIT_WINDOW = 'sbew', + MSG_BREAKPOINT_EDIT_WINDOW_CLOSED = 'bewc', MSG_START_NEW_TEAM = 'sttt', MSG_DEBUG_THIS_TEAM = 'dbtt', MSG_SHOW_INSPECTOR_WINDOW = 'sirw', diff --git a/src/apps/debugger/controllers/TeamDebugger.cpp b/src/apps/debugger/controllers/TeamDebugger.cpp index 620eca5e6c..eec35936f6 100644 --- a/src/apps/debugger/controllers/TeamDebugger.cpp +++ b/src/apps/debugger/controllers/TeamDebugger.cpp @@ -582,9 +582,10 @@ TeamDebugger::MessageReceived(BMessage* message) BReference breakpointReference; uint64 address = 0; - if (message->FindPointer("breakpoint", (void**)&breakpoint) == B_OK) + if (message->FindPointer("breakpoint", (void**)&breakpoint) + == B_OK) { breakpointReference.SetTo(breakpoint, true); - else if (message->FindUInt64("address", &address) != B_OK) + } else if (message->FindUInt64("address", &address) != B_OK) break; if (message->what == MSG_SET_BREAKPOINT) { @@ -610,6 +611,45 @@ TeamDebugger::MessageReceived(BMessage* message) break; } + case MSG_SET_BREAKPOINT_CONDITION: + { + UserBreakpoint* breakpoint = NULL; + BReference breakpointReference; + if (message->FindPointer("breakpoint", (void**)&breakpoint) + != B_OK) { + break; + } + + breakpointReference.SetTo(breakpoint, true); + + const char* condition; + if (message->FindString("condition", &condition) != B_OK) + break; + + AutoLocker< ::Team> teamLocker(fTeam); + breakpoint->SetCondition(condition); + fTeam->NotifyUserBreakpointChanged(breakpoint); + + break; + } + + case MSG_CLEAR_BREAKPOINT_CONDITION: + { + UserBreakpoint* breakpoint = NULL; + BReference breakpointReference; + if (message->FindPointer("breakpoint", (void**)&breakpoint) + != B_OK) + break; + + breakpointReference.SetTo(breakpoint, true); + + AutoLocker< ::Team> teamLocker(fTeam); + breakpoint->SetCondition(NULL); + fTeam->NotifyUserBreakpointChanged(breakpoint); + + break; + } + case MSG_STOP_ON_IMAGE_LOAD: { bool enabled; @@ -986,6 +1026,32 @@ TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint, } +void +TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint, + const char* condition) +{ + BMessage message(MSG_SET_BREAKPOINT_CONDITION); + BReference breakpointReference(breakpoint); + if (message.AddPointer("breakpoint", breakpoint) == B_OK + && message.AddString("condition", condition) == B_OK + && PostMessage(&message) == B_OK) { + breakpointReference.Detach(); + } +} + + +void +TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint) +{ + BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION); + BReference breakpointReference(breakpoint); + if (message.AddPointer("breakpoint", breakpoint) == B_OK + && PostMessage(&message) == B_OK) { + breakpointReference.Detach(); + } +} + + void TeamDebugger::ClearBreakpointRequested(target_addr_t address) { diff --git a/src/apps/debugger/controllers/TeamDebugger.h b/src/apps/debugger/controllers/TeamDebugger.h index ef5a9f2345..10e0447698 100644 --- a/src/apps/debugger/controllers/TeamDebugger.h +++ b/src/apps/debugger/controllers/TeamDebugger.h @@ -81,6 +81,11 @@ private: virtual void SetBreakpointEnabledRequested( UserBreakpoint* breakpoint, bool enabled); + virtual void SetBreakpointConditionRequested( + UserBreakpoint* breakpoint, + const char* condition); + virtual void ClearBreakpointConditionRequested( + UserBreakpoint* breakpoint); virtual void ClearBreakpointRequested(target_addr_t address); virtual void ClearBreakpointRequested( UserBreakpoint* breakpoint); diff --git a/src/apps/debugger/user_interface/UserInterface.h b/src/apps/debugger/user_interface/UserInterface.h index 565f0b9edb..e6abffbc44 100644 --- a/src/apps/debugger/user_interface/UserInterface.h +++ b/src/apps/debugger/user_interface/UserInterface.h @@ -109,6 +109,11 @@ public: virtual void SetBreakpointEnabledRequested( UserBreakpoint* breakpoint, bool enabled) = 0; + virtual void SetBreakpointConditionRequested( + UserBreakpoint* breakpoint, + const char* condition) = 0; + virtual void ClearBreakpointConditionRequested( + UserBreakpoint* breakpoint) = 0; virtual void ClearBreakpointRequested( target_addr_t address) = 0; virtual void ClearBreakpointRequested( diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.cpp b/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.cpp new file mode 100644 index 0000000000..a5f5abed8a --- /dev/null +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2014, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#include "BreakpointEditWindow.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "MessageCodes.h" +#include "UserBreakpoint.h" +#include "UserInterface.h" +#include "Team.h" + + +enum { + MSG_SET_BREAK_ALWAYS = 'sbal', + MSG_SET_BREAK_ON_CONDITION = 'sboc', + MSG_SAVE_BREAKPOINT_SETTINGS = 'sbps' +}; + + +BreakpointEditWindow::BreakpointEditWindow(::Team* team, + UserBreakpoint* breakpoint, UserInterfaceListener* listener, + BHandler* target) + : + BWindow(BRect(), "Edit breakpoint", B_FLOATING_WINDOW, + B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), + fTeam(team), + fListener(listener), + fTargetBreakpoint(breakpoint), + fSaveButton(NULL), + fCancelButton(NULL), + fTarget(target) +{ + fTargetBreakpoint->AcquireReference(); +} + + +BreakpointEditWindow::~BreakpointEditWindow() +{ + fTargetBreakpoint->ReleaseReference(); + BMessenger(fTarget).SendMessage(MSG_BREAKPOINT_EDIT_WINDOW_CLOSED); +} + + +BreakpointEditWindow* +BreakpointEditWindow::Create(::Team* team, UserBreakpoint* breakpoint, + UserInterfaceListener* listener, BHandler* target) +{ + BreakpointEditWindow* self = new BreakpointEditWindow( + team, breakpoint, listener, target); + + try { + self->_Init(); + } catch (...) { + delete self; + throw; + } + + return self; + +} + +void +BreakpointEditWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MSG_SET_BREAK_ALWAYS: + fConditionInput->SetEnabled(false); + break; + case MSG_SET_BREAK_ON_CONDITION: + fConditionInput->SetEnabled(true); + break; + case MSG_SAVE_BREAKPOINT_SETTINGS: + { + if (fConditionRadio->Value() == B_CONTROL_ON) { + fListener->SetBreakpointConditionRequested( + fTargetBreakpoint, fConditionInput->Text()); + } else { + fListener->ClearBreakpointConditionRequested( + fTargetBreakpoint); + } + // fall through + } + case B_CANCEL: + Quit(); + break; + + default: + BWindow::MessageReceived(message); + break; + } + +} + + +void +BreakpointEditWindow::Show() +{ + CenterOnScreen(); + BWindow::Show(); +} + + +void +BreakpointEditWindow::_Init() +{ + fConditionInput = new BTextControl(NULL, NULL, NULL); + BLayoutItem* textLayoutItem = fConditionInput->CreateTextViewLayoutItem(); + textLayoutItem->SetExplicitMinSize(BSize(200.0, B_SIZE_UNSET)); + BLayoutBuilder::Group<>(this, B_VERTICAL) + .SetInsets(B_USE_DEFAULT_SPACING) + .Add((fAlwaysRadio = new BRadioButton("Break always", + new BMessage(MSG_SET_BREAK_ALWAYS)))) + .AddGroup(B_HORIZONTAL) + .Add((fConditionRadio = new BRadioButton("Break on condition: ", + new BMessage(MSG_SET_BREAK_ON_CONDITION)))) + .Add(textLayoutItem) + .End() + .AddGroup(B_HORIZONTAL) + .AddGlue() + .Add((fSaveButton = new BButton("Save", + new BMessage(MSG_SAVE_BREAKPOINT_SETTINGS)))) + .Add((fCancelButton = new BButton("Cancel", + new BMessage(B_CANCEL)))) + .End() + .End(); + + AutoLocker< ::Team> teamLocker(fTeam); + if (fTargetBreakpoint->HasCondition()) { + fConditionRadio->SetValue(B_CONTROL_ON); + fConditionInput->SetText(fTargetBreakpoint->Condition()); + } else { + fAlwaysRadio->SetValue(B_CONTROL_ON); + fConditionInput->SetEnabled(false); + } +} diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.h b/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.h new file mode 100644 index 0000000000..a733fd4ad0 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointEditWindow.h @@ -0,0 +1,61 @@ +/* + * Copyright 2014, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef BREAKPOINT_EDIT_WINDOW_H +#define BREAKPOINT_EDIT_WINDOW_H + + +#include + +#include "Team.h" + +#include "types/Types.h" + + +class BButton; +class BRadioButton; +class BTextControl; +class Team; +class UserBreakpoint; +class UserInterfaceListener; + + +class BreakpointEditWindow : public BWindow { +public: + BreakpointEditWindow( + ::Team* team, + UserBreakpoint* breakpoint, + UserInterfaceListener* listener, + BHandler* target); + + ~BreakpointEditWindow(); + + static BreakpointEditWindow* Create(::Team* team, + UserBreakpoint* breakpoint, + UserInterfaceListener* listener, + BHandler* target); + // throws + + virtual void MessageReceived(BMessage* message); + + virtual void Show(); + +private: + void _Init(); + void _UpdateState(); + +private: + ::Team* fTeam; + UserInterfaceListener* fListener; + UserBreakpoint* fTargetBreakpoint; + BTextControl* fConditionInput; + BButton* fSaveButton; + BButton* fCancelButton; + BRadioButton* fAlwaysRadio; + BRadioButton* fConditionRadio; + BHandler* fTarget; +}; + + +#endif // BREAKPOINT_EDIT_WINDOW diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.cpp b/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.cpp index baf5a964da..acd7888256 100644 --- a/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.cpp @@ -31,6 +31,7 @@ BreakpointsView::BreakpointsView(Team* team, Listener* listener) fListView(NULL), fConfigureExceptionsButton(NULL), fToggleBreakpointButton(NULL), + fEditBreakpointButton(NULL), fRemoveBreakpointButton(NULL), fListener(listener) { @@ -96,6 +97,12 @@ BreakpointsView::MessageReceived(BMessage* message) _HandleBreakpointAction(message->what); break; + case MSG_SHOW_BREAKPOINT_EDIT_WINDOW: + message->AddPointer("breakpoint", + fSelectedBreakpoints.ItemAt(0)->GetBreakpoint()); + Window()->PostMessage(message); + break; + default: BGroupView::MessageReceived(message); break; @@ -107,6 +114,7 @@ void BreakpointsView::AttachedToWindow() { fConfigureExceptionsButton->SetTarget(Window()); + fEditBreakpointButton->SetTarget(this); fToggleBreakpointButton->SetTarget(this); fRemoveBreakpointButton->SetTarget(this); } @@ -157,6 +165,7 @@ BreakpointsView::_Init() .Add(fConfigureExceptionsButton = new BButton( "Configure break conditions" B_UTF8_ELLIPSIS)) .Add(fRemoveBreakpointButton = new BButton("Remove")) + .Add(fEditBreakpointButton = new BButton("Edit" B_UTF8_ELLIPSIS)) .Add(fToggleBreakpointButton = new BButton("Toggle")) .End(); @@ -164,6 +173,8 @@ BreakpointsView::_Init() new BMessage(MSG_SHOW_BREAK_CONDITION_CONFIG_WINDOW)); fToggleBreakpointButton->SetMessage(new BMessage(MSG_ENABLE_BREAKPOINT)); fRemoveBreakpointButton->SetMessage(new BMessage(MSG_CLEAR_BREAKPOINT)); + fEditBreakpointButton->SetMessage( + new BMessage(MSG_SHOW_BREAKPOINT_EDIT_WINDOW)); _UpdateButtons(); } @@ -190,6 +201,7 @@ BreakpointsView::_UpdateButtons() hasEnabled = true; else hasDisabled = true; + } break; } @@ -209,6 +221,17 @@ BreakpointsView::_UpdateButtons() } if (valid) { + // only allow condition editing if we have a single + // actual breakpoint selected. + // TODO: allow using this to modify watchpoints as + // well. + if (fSelectedBreakpoints.CountItems() == 1 + && fSelectedBreakpoints.ItemAt(0)->Type() + == BREAKPOINT_PROXY_TYPE_BREAKPOINT) { + fEditBreakpointButton->SetEnabled(true); + } else + fEditBreakpointButton->SetEnabled(false); + // if we have at least one disabled breakpoint in the // selection, we leave the button as an Enable button if (hasEnabled && !hasDisabled) { @@ -226,6 +249,7 @@ BreakpointsView::_UpdateButtons() } else { fToggleBreakpointButton->SetLabel("Enable"); fToggleBreakpointButton->SetEnabled(false); + fEditBreakpointButton->SetEnabled(false); fRemoveBreakpointButton->SetEnabled(false); } } diff --git a/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.h b/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.h index ea10f93d69..4946b46a72 100644 --- a/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.h +++ b/src/apps/debugger/user_interface/gui/team_window/BreakpointsView.h @@ -57,6 +57,7 @@ private: BreakpointProxyList fSelectedBreakpoints; BButton* fConfigureExceptionsButton; BButton* fToggleBreakpointButton; + BButton* fEditBreakpointButton; BButton* fRemoveBreakpointButton; Listener* fListener; }; diff --git a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp index 32c1543e09..d820398629 100644 --- a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp @@ -33,12 +33,14 @@ #include #include +#include "BreakConditionConfigWindow.h" #include "Breakpoint.h" +#include "BreakpointEditWindow.h" #include "ConsoleOutputView.h" #include "CppLanguage.h" #include "CpuState.h" #include "DisassembledCode.h" -#include "BreakConditionConfigWindow.h" +#include "BreakpointEditWindow.h" #include "ExpressionEvaluationWindow.h" #include "FileSourceCode.h" #include "GuiSettingsUtils.h" @@ -136,6 +138,7 @@ TeamWindow::TeamWindow(::Team* team, UserInterfaceListener* listener) fThreadSplitView(NULL), fConsoleSplitView(NULL), fBreakConditionConfigWindow(NULL), + fBreakpointEditWindow(NULL), fInspectorWindow(NULL), fExpressionWindow(NULL), fFilePanel(NULL), @@ -395,6 +398,36 @@ TeamWindow::MessageReceived(BMessage* message) fBreakConditionConfigWindow = NULL; break; } + case MSG_SHOW_BREAKPOINT_EDIT_WINDOW: + { + if (fBreakpointEditWindow != NULL) { + AutoLocker lock(fBreakpointEditWindow); + if (lock.IsLocked()) + fBreakpointEditWindow->Activate(true); + } else { + UserBreakpoint* breakpoint; + if (message->FindPointer("breakpoint", + reinterpret_cast(&breakpoint)) != B_OK) { + break; + } + + try { + fBreakpointEditWindow + = BreakpointEditWindow::Create( + fTeam, breakpoint, fListener, this); + if (fBreakpointEditWindow != NULL) + fBreakpointEditWindow->Show(); + } catch (...) { + // TODO: notify user + } + } + break; + } + case MSG_BREAKPOINT_EDIT_WINDOW_CLOSED: + { + fBreakpointEditWindow = NULL; + break; + } case MSG_SHOW_WATCH_VARIABLE_PROMPT: { target_addr_t address; diff --git a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h index 91a414e177..ec0cd5c5e4 100644 --- a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h +++ b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h @@ -33,6 +33,7 @@ class BStringView; class BTabView; class ConsoleOutputView; class BreakConditionConfigWindow; +class BreakpointEditWindow; class ExpressionEvaluationWindow; class Image; class InspectorWindow; @@ -220,6 +221,7 @@ private: BSplitView* fThreadSplitView; BSplitView* fConsoleSplitView; BreakConditionConfigWindow* fBreakConditionConfigWindow; + BreakpointEditWindow* fBreakpointEditWindow; InspectorWindow* fInspectorWindow; ExpressionEvaluationWindow* fExpressionWindow; GuiTeamUiSettings fUiSettings;