From ac8b67130a537ab4aefbbe70df31659c1d00b8d8 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 16 Jun 2009 21:47:49 +0000 Subject: [PATCH] * Added bits and pieces to the model classes (Team, Thread, Image). * Added beginnings of the team window. Currently only showing the thread list (not updated yet). * Added application startup code and argument parsing. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31073 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/Debugger.cpp | 300 ++++++++++++++++++ src/apps/debugger/Debugger.rdef | 18 ++ src/apps/debugger/Image.h | 3 +- src/apps/debugger/Jamfile | 34 +- src/apps/debugger/Team.cpp | 114 ++++++- src/apps/debugger/Team.h | 31 ++ src/apps/debugger/TeamDebugger.cpp | 56 +++- src/apps/debugger/TeamDebugger.h | 20 +- src/apps/debugger/Thread.h | 3 +- src/apps/debugger/debugger.cpp | 27 -- .../debugger/gui/team_window/TeamWindow.cpp | 111 +++++++ .../debugger/gui/team_window/TeamWindow.h | 51 +++ .../gui/team_window/ThreadListView.cpp | 223 +++++++++++++ .../debugger/gui/team_window/ThreadListView.h | 47 +++ 14 files changed, 987 insertions(+), 51 deletions(-) create mode 100644 src/apps/debugger/Debugger.cpp create mode 100644 src/apps/debugger/Debugger.rdef delete mode 100644 src/apps/debugger/debugger.cpp create mode 100644 src/apps/debugger/gui/team_window/TeamWindow.cpp create mode 100644 src/apps/debugger/gui/team_window/TeamWindow.h create mode 100644 src/apps/debugger/gui/team_window/ThreadListView.cpp create mode 100644 src/apps/debugger/gui/team_window/ThreadListView.h diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp new file mode 100644 index 0000000000..0b360774f5 --- /dev/null +++ b/src/apps/debugger/Debugger.cpp @@ -0,0 +1,300 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include +#include +#include +#include + +#include + +#include +#include + +#include "debug_utils.h" + +#include "TeamDebugger.h" + + +extern const char* __progname; +const char* kProgramName = __progname; + +static const char* const kDebuggerSignature + = "application/x-vnd.Haiku-Debugger"; + + +static const char* kUsage = + "Usage: %s [ ]\n" + " %s [ ] \n" + " %s [ ] --team \n" + " %s [ ] --thread \n" + "\n" + "The first form starts the debugger displaying a requester to choose a\n" + "running team to debug respectively to specify the program to run and\n" + "debug.\n" + "\n" + "The second form runs the given command line and attaches the debugger to\n" + "the new team. Unless specified otherwise the program will be stopped at\n" + "the beginning of its main() function.\n" + "\n" + "The third and fourth forms attach the debugger to a running team. The\n" + "fourth form additionally stops the specified thread.\n" + "\n" + "Options:\n" + " -h, --help - Print this usage info and exit.\n" +; + + +static void +print_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kUsage, kProgramName, kProgramName, + kProgramName, kProgramName); + exit(error ? 1 : 0); +} + + +struct Options { + int commandLineArgc; + const char* const* commandLineArgv; + team_id team; + thread_id thread; + + Options() + : + commandLineArgc(0), + commandLineArgv(NULL), + team(-1), + thread(-1) + { + } +}; + + +static bool +parse_arguments(int argc, const char* const* argv, bool noOutput, + Options& options) +{ +printf("parse_arguments(): argc: %d\n", argc); + + optind = 1; + + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { "team", required_argument, 0, 't' }, + { "thread", required_argument, 0, 'T' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + + int c = getopt_long(argc, (char**)argv, "+h", sLongOptions, NULL); + if (c == -1) + break; + + switch (c) { + case 'h': + if (noOutput) + return false; + print_usage_and_exit(false); + break; + + case 't': + { + options.team = strtol(optarg, NULL, 0); + if (options.team <= 0) { + if (noOutput) + return false; + print_usage_and_exit(true); + } + break; + } + + case 'T': + { + options.thread = strtol(optarg, NULL, 0); + if (options.thread <= 0) { + if (noOutput) + return false; + print_usage_and_exit(true); + } + break; + } + + default: + if (noOutput) + return false; + print_usage_and_exit(true); + break; + } + } + + if (optind < argc) { + options.commandLineArgc = argc - optind; + options.commandLineArgv = argv + optind; + } + + int exclusiveParams = 0; + if (options.team > 0) + exclusiveParams++; + if (options.thread > 0) + exclusiveParams++; + if (options.commandLineArgc > 0) + exclusiveParams++; + +printf("exclusiveParams: %d\n", exclusiveParams); + if (exclusiveParams == 0) { + // TODO: Support! + if (noOutput) + return false; + fprintf(stderr, "Sorry, running without team/thread to debug not " + "supported yet.\n"); + exit(1); + } else if (exclusiveParams != 1) { + if (noOutput) + return false; + print_usage_and_exit(true); + } + + return true; +} + + +class Debugger : public BApplication { +public: + Debugger() + : + BApplication(kDebuggerSignature) + { + } + + ~Debugger() + { + } + + virtual void MessageReceived(BMessage* message) + { + switch (message->what) { + default: + BApplication::MessageReceived(message); + break; + } + } + + virtual void ReadyToRun() + { + } + + virtual void ArgvReceived(int32 argc, char** argv) + { + Options options; + if (!parse_arguments(argc, argv, true, options)) +{ +printf("Debugger::ArgvReceived(): parsing args failed!\n"); + return; +} + + team_id team = options.team; + thread_id thread = options.thread; + bool stopInMain = false; + + // If command line arguments were given, start the program. + if (options.commandLineArgc > 0) { +printf("loading program: \"%s\" ...\n", options.commandLineArgv[0]); + // TODO: What about the CWD? + thread = load_program(options.commandLineArgv, + options.commandLineArgc, false); + if (thread < 0) { + // TODO: Notify the user! + fprintf(stderr, "Error: Failed to load program \"%s\": %s\n", + options.commandLineArgv[0], strerror(thread)); + return; + } + + team = thread; + // main thread ID == team ID + stopInMain = true; + } + + // If we've got + if (team < 0) { +printf("no team yet, getting thread info...\n"); + thread_info threadInfo; + status_t error = get_thread_info(thread, &threadInfo); + if (error != B_OK) { + // TODO: Notify the user! + fprintf(stderr, "Error: Failed to get info for thread \"%ld\": " + "%s\n", thread, strerror(error)); + return; + } + + team = threadInfo.team; + } +printf("team: %ld, thread: %ld\n", team, thread); + + TeamDebugger* debugger = _TeamDebuggerForTeam(team); + if (debugger != NULL) { + // TODO: Activate the respective window! +printf("There's already a debugger for team: %ld\n", team); + return; + } + + debugger = new(std::nothrow) TeamDebugger; + if (debugger == NULL) { + // TODO: Notify the user! + fprintf(stderr, "Error: Out of memory!\n"); + } + + if (debugger->Init(team, thread, stopInMain) == B_OK) +{ +printf("debugger for team %ld created and initialized successfully!\n", team); + fTeamDebuggers.Add(debugger); +} + else + delete debugger; + } + + virtual bool QuitRequested() + { + // TODO:... + return true; + } + +private: + typedef DoublyLinkedList TeamDebuggerList; + +private: + TeamDebugger* _TeamDebuggerForTeam(team_id teamID) const + { + for (TeamDebuggerList::ConstIterator it = fTeamDebuggers.GetIterator(); + TeamDebugger* debugger = it.Next();) { + if (debugger->TeamID() == teamID) + return debugger; + } + + return NULL; + } + +private: + TeamDebuggerList fTeamDebuggers; +}; + + +int +main(int argc, const char* const* argv) +{ + // We test-parse the arguments here, so, when we're started from the + // terminal and there's an instance already running, we can print an error + // message to the terminal, if something's wrong with the arguments. + { + Options options; + parse_arguments(argc, argv, false, options); + } + + Debugger app; + app.Run(); + return 0; +} diff --git a/src/apps/debugger/Debugger.rdef b/src/apps/debugger/Debugger.rdef new file mode 100644 index 0000000000..f1930bdf06 --- /dev/null +++ b/src/apps/debugger/Debugger.rdef @@ -0,0 +1,18 @@ + +resource(1, "BEOS:APP_SIG") #'MIMS' "application/x-vnd.Haiku-Debugger"; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_BETA, + internal = 0, + + short_info = "Debugger", + long_info = "Debugger ©2009 Haiku, Inc." +}; + +resource app_flags B_SINGLE_LAUNCH; + +// TODO: Please give me a nice icon! diff --git a/src/apps/debugger/Image.h b/src/apps/debugger/Image.h index 4a01172640..5ee17ef72d 100644 --- a/src/apps/debugger/Image.h +++ b/src/apps/debugger/Image.h @@ -7,10 +7,11 @@ #include +#include #include -class Image : public DoublyLinkedListLinkImpl { +class Image : public Referenceable, public DoublyLinkedListLinkImpl { public: Image(const image_info& imageInfo); ~Image(); diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 57c8a5db36..a825ad68f0 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -3,11 +3,20 @@ SubDir HAIKU_TOP src apps debugger ; CCFLAGS += -Werror ; C++FLAGS += -Werror ; -UsePrivateHeaders kernel shared ; +UsePrivateHeaders interface kernel shared ; UsePrivateSystemHeaders ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ; + +local debugAnalyzerSources + = [ FDirName $(HAIKU_TOP) src apps debuganalyzer ] ; + +SubDirHdrs [ FDirName $(HAIKU_TOP) src bin debug ] ; +SubDirHdrs [ FDirName $(debugAnalyzerSources) gui ] ; +SubDirHdrs [ FDirName $(debugAnalyzerSources) util ] ; + Application Debugger : - debugger.cpp + Debugger.cpp ElfFile.cpp Image.cpp @@ -15,6 +24,13 @@ Application Debugger : Team.cpp Thread.cpp + # DebugAnalyzer:util + Variant.cpp + + # gui/team_window + TeamWindow.cpp + ThreadListView.cpp + # DWARF # attribute_classes.cpp # AttributeValue.cpp @@ -24,7 +40,19 @@ Application Debugger : # SourceLanguageInfo.cpp # tag_names.cpp - : $(TARGET_LIBSUPC++) be + : + DebugAnalyzer_gui_table.o + + debug_utils.a + libcolumnlistview.a + + $(TARGET_LIBSTDC++) + be + + : Debugger.rdef ; +SEARCH on [ FGristFiles Variant.cpp ] + = [ FDirName $(debugAnalyzerSources) util ] ; + HaikuSubInclude gui running_teams_window ; diff --git a/src/apps/debugger/Team.cpp b/src/apps/debugger/Team.cpp index b4818ee1dd..ae6186e5fb 100644 --- a/src/apps/debugger/Team.cpp +++ b/src/apps/debugger/Team.cpp @@ -8,6 +8,9 @@ #include +// #pragma mark - Team + + Team::Team(team_id teamID) : fID(teamID) @@ -18,10 +21,10 @@ Team::Team(team_id teamID) Team::~Team() { while (Image* image = fImages.RemoveHead()) - delete image; + image->RemoveReference(); while (Thread* thread = fThreads.RemoveHead()) - delete thread; + thread->RemoveReference(); } @@ -43,6 +46,7 @@ void Team::AddThread(Thread* thread) { fThreads.Add(thread); + _NotifyThreadAdded(thread); } @@ -73,6 +77,7 @@ void Team::RemoveThread(Thread* thread) { fThreads.Remove(thread); + _NotifyThreadRemoved(thread); } @@ -84,7 +89,7 @@ Team::RemoveThread(thread_id threadID) return false; RemoveThread(thread); - delete thread; + thread->RemoveReference(); return true; } @@ -102,10 +107,18 @@ Team::ThreadByID(thread_id threadID) const } +const ThreadList& +Team::Threads() const +{ + return fThreads; +} + + void Team::AddImage(Image* image) { fImages.Add(image); + _NotifyImageAdded(image); } @@ -135,6 +148,7 @@ void Team::RemoveImage(Image* image) { fImages.Remove(image); + _NotifyImageRemoved(image); } @@ -146,7 +160,7 @@ Team::RemoveImage(image_id imageID) return false; RemoveImage(image); - delete image; + image->RemoveReference(); return true; } @@ -162,3 +176,95 @@ Team::ImageByID(image_id imageID) const return NULL; } + + +const ImageList& +Team::Images() const +{ + return fImages; +} + + +void +Team::AddListener(Listener* listener) +{ + fListeners.Add(listener); +} + + +void +Team::RemoveListener(Listener* listener) +{ + fListeners.Remove(listener); +} + + +void +Team::_NotifyThreadAdded(Thread* thread) +{ + for (ListenerList::Iterator it = fListeners.GetIterator(); + Listener* listener = it.Next();) { + listener->ThreadAdded(this, thread); + } +} + + +void +Team::_NotifyThreadRemoved(Thread* thread) +{ + for (ListenerList::Iterator it = fListeners.GetIterator(); + Listener* listener = it.Next();) { + listener->ThreadRemoved(this, thread); + } +} + + +void +Team::_NotifyImageAdded(Image* image) +{ + for (ListenerList::Iterator it = fListeners.GetIterator(); + Listener* listener = it.Next();) { + listener->ImageAdded(this, image); + } +} + + +void +Team::_NotifyImageRemoved(Image* image) +{ + for (ListenerList::Iterator it = fListeners.GetIterator(); + Listener* listener = it.Next();) { + listener->ImageRemoved(this, image); + } +} + + +// #pragma mark - Listener + +Team::Listener::~Listener() +{ +} + + +void +Team::Listener::ThreadAdded(Team* team, Thread* thread) +{ +} + + +void +Team::Listener::ThreadRemoved(Team* team, Thread* thread) +{ +} + + +void +Team::Listener::ImageAdded(Team* team, Image* image) +{ +} + + +void +Team::Listener::ImageRemoved(Team* team, Image* image) +{ +} diff --git a/src/apps/debugger/Team.h b/src/apps/debugger/Team.h index 3cabf22ee2..48ec7e8a7f 100644 --- a/src/apps/debugger/Team.h +++ b/src/apps/debugger/Team.h @@ -12,6 +12,9 @@ class Team : public BLocker { +public: + class Listener; + public: Team(team_id teamID); ~Team(); @@ -29,6 +32,7 @@ public: void RemoveThread(Thread* thread); bool RemoveThread(thread_id threadID); Thread* ThreadByID(thread_id threadID) const; + const ThreadList& Threads() const; void AddImage(Image* image); status_t AddImage(const image_info& imageInfo, @@ -36,12 +40,39 @@ public: void RemoveImage(Image* image); bool RemoveImage(image_id imageID); Image* ImageByID(image_id imageID) const; + const ImageList& Images() const; + + void AddListener(Listener* listener); + void RemoveListener(Listener* listener); + +private: + typedef DoublyLinkedList ListenerList; + +private: + void _NotifyThreadAdded(Thread* thread); + void _NotifyThreadRemoved(Thread* thread); + void _NotifyImageAdded(Image* image); + void _NotifyImageRemoved(Image* image); private: team_id fID; BString fName; ThreadList fThreads; ImageList fImages; + ListenerList fListeners; }; + +class Team::Listener : public DoublyLinkedListLinkImpl { +public: + virtual ~Listener(); + + virtual void ThreadAdded(Team* team, Thread* thread); + virtual void ThreadRemoved(Team* team, Thread* thread); + + virtual void ImageAdded(Team* team, Image* image); + virtual void ImageRemoved(Team* team, Image* image); +}; + + #endif // TEAM_H diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index 9a1b1cd1fd..4fd3a63640 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -9,6 +9,8 @@ #include +#include + #include #include "Team.h" @@ -16,12 +18,13 @@ TeamDebugger::TeamDebugger() : - fLock("team debugger"), + BLooper("team debugger"), fTeam(NULL), fTeamID(-1), fDebuggerPort(-1), fNubPort(-1), fDebugEventListener(-1), + fTeamWindow(NULL), fTerminating(false) { } @@ -29,7 +32,7 @@ TeamDebugger::TeamDebugger() TeamDebugger::~TeamDebugger() { - AutoLocker locker(fLock); + AutoLocker locker(this); fTerminating = true; @@ -46,22 +49,18 @@ TeamDebugger::~TeamDebugger() status_t -TeamDebugger::Init(team_id teamID) +TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain) { fTeamID = teamID; - status_t error = fLock.InitCheck(); - if (error != B_OK) - return error; - // check whether the team exists at all team_info teamInfo; - error = get_team_info(fTeamID, &teamInfo); + status_t error = get_team_info(fTeamID, &teamInfo); if (error != B_OK) return error; // create a team object - fTeam = new(std::nothrow) Team(fTeamID); + fTeam = new(std::nothrow) ::Team(fTeamID); if (fTeam == NULL) return B_NO_MEMORY; @@ -86,7 +85,7 @@ TeamDebugger::Init(team_id teamID) // TODO: Set the debug event flags! // get the initial state of the team - AutoLocker teamLocker(fTeam); + AutoLocker< ::Team> teamLocker(fTeam); thread_info threadInfo; int32 cookie = 0; @@ -113,10 +112,47 @@ TeamDebugger::Init(team_id teamID) resume_thread(fDebugEventListener); + // run looper + thread_id looperThread = Run(); + if (looperThread < 0) + return looperThread; + + // create the team window + try { + fTeamWindow = TeamWindow::Create(fTeam, this); + } catch (...) { + // TODO: Notify the user! + fprintf(stderr, "Error: Failed to create team window!\n"); + return B_NO_MEMORY; + } + + fTeamWindow->Show(); + + // if requested, stop the given thread + if (threadID >= 0) { + if (stopInMain) { + // TODO: Set a temporary breakpoint in main and run the thread. + } else { + debug_thread(threadID); + // TODO: Superfluous, if the thread is already stopped. + } + } + return B_OK; } +void +TeamDebugger::MessageReceived(BMessage* message) +{ + switch (message->what) { + default: + BLooper::MessageReceived(message); + break; + } +} + + /*static*/ status_t TeamDebugger::_DebugEventListenerEntry(void* data) { diff --git a/src/apps/debugger/TeamDebugger.h b/src/apps/debugger/TeamDebugger.h index 99b9e34822..9de07407e7 100644 --- a/src/apps/debugger/TeamDebugger.h +++ b/src/apps/debugger/TeamDebugger.h @@ -6,19 +6,29 @@ #define TEAM_DEBUGGER_H #include -#include +#include + +#include + +#include "TeamWindow.h" class Team; -class TeamDebugger { +class TeamDebugger : public DoublyLinkedListLinkImpl, + private BLooper, private TeamWindow::Listener { public: TeamDebugger(); ~TeamDebugger(); - status_t Init(team_id teamID); + status_t Init(team_id teamID, thread_id threadID, + bool stopInMain); + team_id TeamID() const { return fTeamID; } + +private: + virtual void MessageReceived(BMessage* message); private: static status_t _DebugEventListenerEntry(void* data); @@ -28,12 +38,12 @@ private: const debug_debugger_message_data& message); private: - BLocker fLock; - Team* fTeam; + ::Team* fTeam; team_id fTeamID; port_id fDebuggerPort; port_id fNubPort; thread_id fDebugEventListener; + TeamWindow* fTeamWindow; volatile bool fTerminating; }; diff --git a/src/apps/debugger/Thread.h b/src/apps/debugger/Thread.h index 74bf62aa19..37b1bd4fff 100644 --- a/src/apps/debugger/Thread.h +++ b/src/apps/debugger/Thread.h @@ -8,10 +8,11 @@ #include #include +#include #include -class Thread : public DoublyLinkedListLinkImpl { +class Thread : public Referenceable, public DoublyLinkedListLinkImpl { public: Thread(thread_id threadID); ~Thread(); diff --git a/src/apps/debugger/debugger.cpp b/src/apps/debugger/debugger.cpp deleted file mode 100644 index 1077519e80..0000000000 --- a/src/apps/debugger/debugger.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ - -#include - -//#include "DwarfManager.h" - - -int -main(int argc, const char* const* argv) -{ - if (argc != 2) { - fprintf(stderr, "Usage:...\n"); - return 1; - } - - const char* fileName = argv[1]; - -// DwarfManager manager; -// manager.LoadFile(fileName); -// manager.FinishLoading(); -(void)fileName; - - return 0; -} diff --git a/src/apps/debugger/gui/team_window/TeamWindow.cpp b/src/apps/debugger/gui/team_window/TeamWindow.cpp new file mode 100644 index 0000000000..17491e90f8 --- /dev/null +++ b/src/apps/debugger/gui/team_window/TeamWindow.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "TeamWindow.h" + +#include +#include +#include + +#include "Team.h" +#include "ThreadListView.h" + + +// #pragma mark - TeamWindow + + +TeamWindow::TeamWindow(::Team* team, Listener* listener) + : + BWindow(BRect(100, 100, 399, 299), _GetWindowTitle(team).String(), + B_DOCUMENT_WINDOW, B_ASYNCHRONOUS_CONTROLS), + fTeam(team), + fListener(listener), + fTabView(NULL), + fThreadListView(NULL) +{ +} + + +TeamWindow::~TeamWindow() +{ +} + + +/*static*/ TeamWindow* +TeamWindow::Create(::Team* team, Listener* listener) +{ + TeamWindow* self = new TeamWindow(team, listener); + + try { + self->_Init(); + } catch (...) { + delete self; + throw; + } + + return self; +} + + +void +TeamWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + default: + BWindow::MessageReceived(message); + break; + } +} + + +bool +TeamWindow::QuitRequested() +{ + return fListener->TeamWindowQuitRequested(this); +} + + +/*static*/ BString +TeamWindow::_GetWindowTitle(::Team* team) +{ + BString name = team->Name(); + if (team->ID() >= 0) + name << " (" << team->ID() << ")"; + return name; +} + + +void +TeamWindow::_Init() +{ + BGroupLayout* rootLayout = new BGroupLayout(B_VERTICAL); + SetLayout(rootLayout); + + fTabView = new BTabView("tab view"); + + BGroupLayoutBuilder(rootLayout) + .Add(fTabView); + + fTabView->AddTab(fThreadListView = ThreadListView::Create()); +// fTabView->AddTab(fTeamsPage = new TeamsPage(this)); +// fTabView->AddTab(fThreadsPage = new ThreadsPage(this)); + + fThreadListView->SetTeam(fTeam); +} + + +// #pragma mark - Listener + + +TeamWindow::Listener::~Listener() +{ +} + + +bool +TeamWindow::Listener::TeamWindowQuitRequested(TeamWindow* window) +{ + return true; +} diff --git a/src/apps/debugger/gui/team_window/TeamWindow.h b/src/apps/debugger/gui/team_window/TeamWindow.h new file mode 100644 index 0000000000..670cc42dcf --- /dev/null +++ b/src/apps/debugger/gui/team_window/TeamWindow.h @@ -0,0 +1,51 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TEAM_WINDOW_H +#define TEAM_WINDOW_H + +#include +#include + + +class BTabView; +class Team; +class ThreadListView; + + +class TeamWindow : public BWindow { +public: + class Listener; + +public: + TeamWindow(::Team* team, Listener* listener); + ~TeamWindow(); + + static TeamWindow* Create(::Team* team, Listener* listener); + // throws + + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + +private: + static BString _GetWindowTitle(::Team* team); + void _Init(); + +private: + ::Team* fTeam; + Listener* fListener; + BTabView* fTabView; + ThreadListView* fThreadListView; +}; + + +class TeamWindow::Listener { +public: + virtual ~Listener(); + + virtual bool TeamWindowQuitRequested(TeamWindow* window); +}; + + +#endif // TEAM_WINDOW_H diff --git a/src/apps/debugger/gui/team_window/ThreadListView.cpp b/src/apps/debugger/gui/team_window/ThreadListView.cpp new file mode 100644 index 0000000000..ebff1a72d5 --- /dev/null +++ b/src/apps/debugger/gui/team_window/ThreadListView.cpp @@ -0,0 +1,223 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "ThreadListView.h" + +#include + +#include + +#include +#include + +#include +#include + +#include "table/TableColumns.h" + + +enum { + MSG_SYNC_THREAD_LIST = 'sytl' +}; + + +// #pragma mark - ThreadsTableModel + + +class ThreadListView::ThreadsTableModel : public TableModel { +public: + ThreadsTableModel(Team* team) + : + fTeam(team) + { + Update(); + } + + ~ThreadsTableModel() + { + fTeam = NULL; + Update(); + } + + bool Update() + { + for (int32 i = 0; Thread* thread = fThreads.ItemAt(i); i++) + thread->RemoveReference(); + fThreads.MakeEmpty(); + + if (fTeam == NULL) + return true; + + AutoLocker locker(fTeam); + + for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator(); + Thread* thread = it.Next();) { + if (!fThreads.AddItem(thread)) + return false; + + thread->AddReference(); + } + + return true; + } + + virtual int32 CountColumns() const + { + return 2; + } + + virtual int32 CountRows() const + { + return fThreads.CountItems(); + } + + virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, Variant& value) + { + Thread* thread = fThreads.ItemAt(rowIndex); + if (thread == NULL) + return false; + + switch (columnIndex) { + case 0: + value.SetTo(thread->ID()); + return true; + case 1: + value.SetTo(thread->Name(), VARIANT_DONT_COPY_DATA); + return true; + default: + return false; + } + } + + Thread* ThreadAt(int32 index) const + { + return fThreads.ItemAt(index); + } + +private: + Team* fTeam; + BObjectList fThreads; +}; + + +// #pragma mark - ThreadListView + + +ThreadListView::ThreadListView() + : + BGroupView(B_VERTICAL), + fTeam(NULL), + fThreadsTable(NULL), + fThreadsTableModel(NULL) +{ + SetName("Threads"); +} + + +ThreadListView::~ThreadListView() +{ + SetTeam(NULL); + fThreadsTable->SetTableModel(NULL); + delete fThreadsTableModel; +} + + +/*static*/ ThreadListView* +ThreadListView::Create() +{ + ThreadListView* self = new ThreadListView; + + try { + self->_Init(); + } catch (...) { + delete self; + throw; + } + + return self; +} + + +void +ThreadListView::SetTeam(Team* team) +{ + if (team == fTeam) + return; + + if (fTeam != NULL) { + fTeam->RemoveListener(this); + fThreadsTable->SetTableModel(NULL); + delete fThreadsTableModel; + fThreadsTableModel = NULL; + } + + fTeam = team; + + if (fTeam != NULL) { + fThreadsTableModel = new(std::nothrow) ThreadsTableModel(fTeam); + fThreadsTable->SetTableModel(fThreadsTableModel); + fThreadsTable->ResizeAllColumnsToPreferred(); + fTeam->AddListener(this); + } +} + + +void +ThreadListView::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MSG_SYNC_THREAD_LIST: + if (fThreadsTableModel != NULL) { + fThreadsTable->SetTableModel(NULL); + fThreadsTableModel->Update(); + fThreadsTable->SetTableModel(fThreadsTableModel); + } + break; + default: + BGroupView::MessageReceived(message); + break; + } +} + + +void +ThreadListView::ThreadAdded(Team* team, Thread* thread) +{ + Looper()->PostMessage(MSG_SYNC_THREAD_LIST, this); +} + + +void +ThreadListView::ThreadRemoved(Team* team, Thread* thread) +{ + Looper()->PostMessage(MSG_SYNC_THREAD_LIST, this); +} + + +void +ThreadListView::TableRowInvoked(Table* table, int32 rowIndex) +{ +// if (fThreadsTableModel != NULL) { +// Thread* thread = fThreadsTableModel->ThreadAt(rowIndex); +// if (thread != NULL) +// fParent->OpenThreadWindow(thread); +// } +} + + +void +ThreadListView::_Init() +{ + fThreadsTable = new Table("threads list", 0); + AddChild(fThreadsTable->ToView()); + + // columns + fThreadsTable->AddColumn(new Int32TableColumn(0, "ID", 40, 20, 1000, + B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT)); + fThreadsTable->AddColumn(new StringTableColumn(1, "Name", 80, 40, 1000, + B_TRUNCATE_END, B_ALIGN_LEFT)); + + fThreadsTable->AddTableListener(this); +} diff --git a/src/apps/debugger/gui/team_window/ThreadListView.h b/src/apps/debugger/gui/team_window/ThreadListView.h new file mode 100644 index 0000000000..8f3b7952b4 --- /dev/null +++ b/src/apps/debugger/gui/team_window/ThreadListView.h @@ -0,0 +1,47 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef THREAD_LIST_VIEW_H +#define THREAD_LIST_VIEW_H + +#include + +#include "table/Table.h" +#include "Team.h" + + +class ThreadListView : public BGroupView, private Team::Listener, + private TableListener { +public: + ThreadListView(); + ~ThreadListView(); + + static ThreadListView* Create(); + // throws + + void SetTeam(Team* team); + + virtual void MessageReceived(BMessage* message); + +private: + class ThreadsTableModel; + +private: + // Team::Listener + virtual void ThreadAdded(Team* team, Thread* thread); + virtual void ThreadRemoved(Team* team, Thread* thread); + + // TableListener + virtual void TableRowInvoked(Table* table, int32 rowIndex); + + void _Init(); + +private: + Team* fTeam; + Table* fThreadsTable; + ThreadsTableModel* fThreadsTableModel; +}; + + +#endif // THREAD_LIST_VIEW_H