xref: /haiku/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp (revision aed35104852941f0f6f3d1dcc5338b5f337d0a3c)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2010-2012, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "TeamWindow.h"
9 
10 #include <stdio.h>
11 
12 #include <Button.h>
13 #include <FilePanel.h>
14 #include <LayoutBuilder.h>
15 #include <Menu.h>
16 #include <MenuBar.h>
17 #include <MenuItem.h>
18 #include <Message.h>
19 #include <MessageFilter.h>
20 #include <Path.h>
21 #include <StringView.h>
22 #include <TabView.h>
23 #include <ScrollView.h>
24 #include <SplitView.h>
25 #include <TextView.h>
26 
27 #include <AutoLocker.h>
28 
29 #include "Breakpoint.h"
30 #include "CpuState.h"
31 #include "DisassembledCode.h"
32 #include "FileSourceCode.h"
33 #include "GuiSettingsUtils.h"
34 #include "GuiTeamUiSettings.h"
35 #include "Image.h"
36 #include "ImageDebugInfo.h"
37 #include "InspectorWindow.h"
38 #include "LocatableFile.h"
39 #include "MessageCodes.h"
40 #include "RegistersView.h"
41 #include "StackTrace.h"
42 #include "StackTraceView.h"
43 #include "Tracing.h"
44 #include "TypeComponentPath.h"
45 #include "UserInterface.h"
46 #include "Variable.h"
47 
48 
49 enum {
50 	MAIN_TAB_INDEX_THREADS	= 0,
51 	MAIN_TAB_INDEX_IMAGES	= 1
52 };
53 
54 
55 enum {
56 	MSG_LOCATE_SOURCE_IF_NEEDED = 'lsin'
57 };
58 
59 
60 class PathViewMessageFilter : public BMessageFilter {
61 public:
62 		PathViewMessageFilter(BMessenger teamWindow)
63 			:
64 			BMessageFilter(B_MOUSE_UP),
65 			fTeamWindowMessenger(teamWindow)
66 		{
67 		}
68 
69 		virtual filter_result Filter(BMessage*, BHandler**)
70 		{
71 			fTeamWindowMessenger.SendMessage(MSG_LOCATE_SOURCE_IF_NEEDED);
72 
73 			return B_DISPATCH_MESSAGE;
74 		}
75 
76 private:
77 		BMessenger fTeamWindowMessenger;
78 };
79 
80 
81 // #pragma mark - TeamWindow
82 
83 
84 TeamWindow::TeamWindow(::Team* team, UserInterfaceListener* listener)
85 	:
86 	BWindow(BRect(100, 100, 899, 699), "Team", B_TITLED_WINDOW,
87 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
88 	fTeam(team),
89 	fActiveThread(NULL),
90 	fActiveImage(NULL),
91 	fActiveStackTrace(NULL),
92 	fActiveStackFrame(NULL),
93 	fActiveBreakpoint(NULL),
94 	fActiveFunction(NULL),
95 	fActiveSourceCode(NULL),
96 	fActiveSourceObject(ACTIVE_SOURCE_NONE),
97 	fListener(listener),
98 	fTabView(NULL),
99 	fLocalsTabView(NULL),
100 	fThreadListView(NULL),
101 	fImageListView(NULL),
102 	fImageFunctionsView(NULL),
103 	fBreakpointsView(NULL),
104 	fVariablesView(NULL),
105 	fRegistersView(NULL),
106 	fStackTraceView(NULL),
107 	fSourceView(NULL),
108 	fRunButton(NULL),
109 	fStepOverButton(NULL),
110 	fStepIntoButton(NULL),
111 	fStepOutButton(NULL),
112 	fInspectorWindow(NULL),
113 	fSourceLocatePanel(NULL)
114 {
115 	fTeam->Lock();
116 	BString name = fTeam->Name();
117 	fTeam->Unlock();
118 	if (fTeam->ID() >= 0)
119 		name << " (" << fTeam->ID() << ")";
120 	SetTitle(name.String());
121 
122 	fTeam->AddListener(this);
123 }
124 
125 
126 TeamWindow::~TeamWindow()
127 {
128 	if (fThreadListView != NULL)
129 		fThreadListView->UnsetListener();
130 	if (fStackTraceView != NULL)
131 		fStackTraceView->UnsetListener();
132 	if (fSourceView != NULL)
133 		fSourceView->UnsetListener();
134 
135 	fTeam->RemoveListener(this);
136 
137 	_SetActiveSourceCode(NULL);
138 	_SetActiveFunction(NULL);
139 	_SetActiveBreakpoint(NULL);
140 	_SetActiveStackFrame(NULL);
141 	_SetActiveStackTrace(NULL);
142 	_SetActiveImage(NULL);
143 	_SetActiveThread(NULL);
144 
145 	delete fSourceLocatePanel;
146 }
147 
148 
149 /*static*/ TeamWindow*
150 TeamWindow::Create(::Team* team, UserInterfaceListener* listener)
151 {
152 	TeamWindow* self = new TeamWindow(team, listener);
153 
154 	try {
155 		self->_Init();
156 	} catch (...) {
157 		delete self;
158 		throw;
159 	}
160 
161 	return self;
162 }
163 
164 
165 void
166 TeamWindow::DispatchMessage(BMessage* message, BHandler* handler)
167 {
168 	// Handle function key shortcuts for stepping
169 	switch (message->what) {
170 		case B_KEY_DOWN:
171 			if (fActiveThread != NULL) {
172 				int32 key;
173 				uint32 modifiers;
174 				if (message->FindInt32("key", &key) == B_OK
175 					&& message->FindInt32("modifiers", (int32*)&modifiers)
176 					== B_OK) {
177 					switch (key) {
178 						case B_F5_KEY:
179 							fListener->ThreadActionRequested(
180 								fActiveThread->ID(), MSG_THREAD_RUN);
181 							break;
182 						case B_F10_KEY:
183 							fListener->ThreadActionRequested(
184 								fActiveThread->ID(), MSG_THREAD_STEP_OVER);
185 							break;
186 						case B_F11_KEY:
187 							if ((modifiers & B_SHIFT_KEY) != 0) {
188 								fListener->ThreadActionRequested(
189 									fActiveThread->ID(), MSG_THREAD_STEP_OUT);
190 							} else {
191 								fListener->ThreadActionRequested(
192 									fActiveThread->ID(), MSG_THREAD_STEP_INTO);
193 							}
194 							break;
195 						default:
196 							break;
197 					}
198 				}
199 			}
200 			break;
201 
202 		case B_COPY:
203 		case B_SELECT_ALL:
204 			BView* focusView = CurrentFocus();
205 			if (focusView != NULL)
206 				focusView->MessageReceived(message);
207 			break;
208 	}
209 	BWindow::DispatchMessage(message, handler);
210 }
211 
212 
213 void
214 TeamWindow::MessageReceived(BMessage* message)
215 {
216 	switch (message->what) {
217 		case MSG_SHOW_INSPECTOR_WINDOW:
218 		{
219 			if (fInspectorWindow) {
220 				fInspectorWindow->Activate(true);
221 			} else {
222 				try {
223 					fInspectorWindow = InspectorWindow::Create(fTeam,
224 						fListener, this);
225 					if (fInspectorWindow != NULL) {
226 						BMessage settings;
227 						fInspectorWindow->LoadSettings(fUiSettings);
228 						fInspectorWindow->Show();
229 					}
230 	           	} catch (...) {
231 	           		// TODO: notify user
232 	           	}
233 			}
234 
235 			target_addr_t address;
236 			if (message->FindUInt64("address", &address) == B_OK) {
237 				BMessage addressMessage(MSG_INSPECT_ADDRESS);
238 				addressMessage.AddUInt64("address", address);
239 				fInspectorWindow->PostMessage(&addressMessage);
240 			}
241            	break;
242 		}
243 		case MSG_INSPECTOR_WINDOW_CLOSED:
244 		{
245 			_SaveInspectorSettings(CurrentMessage());
246 			fInspectorWindow = NULL;
247 			break;
248 
249 		}
250 		case B_REFS_RECEIVED:
251 		{
252 			entry_ref locatedPath;
253 			message->FindRef("refs", &locatedPath);
254 			_HandleResolveMissingSourceFile(locatedPath);
255 			break;
256 		}
257 		case MSG_LOCATE_SOURCE_IF_NEEDED:
258 		{
259 			if (fActiveFunction != NULL
260 				&& fActiveFunction->GetFunctionDebugInfo()
261 					->SourceFile() != NULL && fActiveSourceCode != NULL
262 				&& fActiveSourceCode->GetSourceFile() == NULL) {
263 				try {
264 					if (fSourceLocatePanel == NULL) {
265 						fSourceLocatePanel = new BFilePanel(B_OPEN_PANEL,
266 							new BMessenger(this));
267 					}
268 					fSourceLocatePanel->Show();
269 				} catch (...) {
270 					delete fSourceLocatePanel;
271 					fSourceLocatePanel = NULL;
272 				}
273 			}
274 			break;
275 		}
276 		case MSG_THREAD_RUN:
277 		case MSG_THREAD_STOP:
278 		case MSG_THREAD_STEP_OVER:
279 		case MSG_THREAD_STEP_INTO:
280 		case MSG_THREAD_STEP_OUT:
281 			if (fActiveThread != NULL) {
282 				fListener->ThreadActionRequested(fActiveThread->ID(),
283 					message->what);
284 			}
285 			break;
286 
287 		case MSG_THREAD_STATE_CHANGED:
288 		{
289 			int32 threadID;
290 			if (message->FindInt32("thread", &threadID) != B_OK)
291 				break;
292 
293 			_HandleThreadStateChanged(threadID);
294 			break;
295 		}
296 		case MSG_THREAD_CPU_STATE_CHANGED:
297 		{
298 			int32 threadID;
299 			if (message->FindInt32("thread", &threadID) != B_OK)
300 				break;
301 
302 			_HandleCpuStateChanged(threadID);
303 			break;
304 		}
305 
306 		case MSG_THREAD_STACK_TRACE_CHANGED:
307 		{
308 			int32 threadID;
309 			if (message->FindInt32("thread", &threadID) != B_OK)
310 				break;
311 
312 			_HandleStackTraceChanged(threadID);
313 			break;
314 		}
315 
316 		case MSG_IMAGE_DEBUG_INFO_CHANGED:
317 		{
318 			int32 imageID;
319 			if (message->FindInt32("image", &imageID) != B_OK)
320 				break;
321 
322 			_HandleImageDebugInfoChanged(imageID);
323 			break;
324 		}
325 
326 		case MSG_USER_BREAKPOINT_CHANGED:
327 		{
328 			UserBreakpoint* breakpoint;
329 			if (message->FindPointer("breakpoint", (void**)&breakpoint) != B_OK)
330 				break;
331 			BReference<UserBreakpoint> breakpointReference(breakpoint, true);
332 
333 			_HandleUserBreakpointChanged(breakpoint);
334 			break;
335 		}
336 
337 		case MSG_FUNCTION_SOURCE_CODE_CHANGED:
338 		{
339 			_HandleSourceCodeChanged();
340 			break;
341 		}
342 
343 		default:
344 			BWindow::MessageReceived(message);
345 			break;
346 	}
347 }
348 
349 
350 bool
351 TeamWindow::QuitRequested()
352 {
353 	fListener->UserInterfaceQuitRequested();
354 
355 	return false;
356 }
357 
358 
359 status_t
360 TeamWindow::LoadSettings(const GuiTeamUiSettings* settings)
361 {
362 	AutoLocker<BWindow> lock(this);
363 	if (!lock.IsLocked())
364 		return B_ERROR;
365 
366 	BMessage teamWindowSettings;
367 	// no settings stored yet
368 	if (settings->Settings("teamWindow", teamWindowSettings) != B_OK)
369 		return B_OK;
370 
371 	BRect frame;
372 	if (teamWindowSettings.FindRect("frame", &frame) == B_OK) {
373 		ResizeTo(frame.Width(), frame.Height());
374 		MoveTo(frame.left, frame.top);
375 	}
376 
377 	BMessage archive;
378 	if (teamWindowSettings.FindMessage("sourceSplit", &archive) == B_OK)
379 		GuiSettingsUtils::UnarchiveSplitView(archive, fSourceSplitView);
380 
381 	if (teamWindowSettings.FindMessage("functionSplit", &archive) == B_OK)
382 		GuiSettingsUtils::UnarchiveSplitView(archive, fFunctionSplitView);
383 
384 	if (teamWindowSettings.FindMessage("imageSplit", &archive) == B_OK)
385 		GuiSettingsUtils::UnarchiveSplitView(archive, fImageSplitView);
386 
387 	if (teamWindowSettings.FindMessage("threadSplit", &archive) == B_OK)
388 		GuiSettingsUtils::UnarchiveSplitView(archive, fThreadSplitView);
389 
390 	if (teamWindowSettings.FindMessage("imageListView", &archive) == B_OK)
391 		fImageListView->LoadSettings(archive);
392 
393 	if (teamWindowSettings.FindMessage("imageFunctionsView", &archive) == B_OK)
394 		fImageFunctionsView->LoadSettings(archive);
395 
396 	if (teamWindowSettings.FindMessage("threadListView", &archive) == B_OK)
397 		fThreadListView->LoadSettings(archive);
398 
399 	if (teamWindowSettings.FindMessage("variablesView", &archive) == B_OK)
400 		fVariablesView->LoadSettings(archive);
401 
402 	if (teamWindowSettings.FindMessage("registersView", &archive) == B_OK)
403 		fRegistersView->LoadSettings(archive);
404 
405 	if (teamWindowSettings.FindMessage("stackTraceView", &archive) == B_OK)
406 		fStackTraceView->LoadSettings(archive);
407 
408 	if (teamWindowSettings.FindMessage("breakpointsView", &archive) == B_OK)
409 		fBreakpointsView->LoadSettings(archive);
410 
411 	fUiSettings = *settings;
412 
413 	return B_OK;
414 }
415 
416 
417 status_t
418 TeamWindow::SaveSettings(GuiTeamUiSettings* settings)
419 {
420 	AutoLocker<BWindow> lock(this);
421 	if (!lock.IsLocked())
422 		return B_ERROR;
423 
424 	BMessage inspectorSettings;
425 	if (fUiSettings.Settings("inspectorWindow", inspectorSettings) == B_OK) {
426 		if (!settings->AddSettings("inspectorWindow", inspectorSettings))
427 			return B_NO_MEMORY;
428 	}
429 
430 	BMessage archive;
431 	BMessage teamWindowSettings;
432 	if (teamWindowSettings.AddRect("frame", Frame()) != B_OK)
433 		return B_NO_MEMORY;
434 
435 	if (GuiSettingsUtils::ArchiveSplitView(archive, fSourceSplitView) != B_OK)
436 		return B_NO_MEMORY;
437 	if (teamWindowSettings.AddMessage("sourceSplit", &archive) != B_OK)
438 		return B_NO_MEMORY;
439 
440 	if (GuiSettingsUtils::ArchiveSplitView(archive, fFunctionSplitView) != B_OK)
441 		return B_NO_MEMORY;
442 	if (teamWindowSettings.AddMessage("functionSplit", &archive) != B_OK)
443 		return B_NO_MEMORY;
444 
445 	if (GuiSettingsUtils::ArchiveSplitView(archive, fImageSplitView) != B_OK)
446 		return B_NO_MEMORY;
447 	if (teamWindowSettings.AddMessage("imageSplit", &archive))
448 		return B_NO_MEMORY;
449 
450 	if (GuiSettingsUtils::ArchiveSplitView(archive, fThreadSplitView) != B_OK)
451 		return B_NO_MEMORY;
452 	if (teamWindowSettings.AddMessage("threadSplit", &archive))
453 		return B_NO_MEMORY;
454 
455 	if (fImageListView->SaveSettings(archive) != B_OK)
456 		return B_NO_MEMORY;
457 	if (teamWindowSettings.AddMessage("imageListView", &archive))
458 		return B_NO_MEMORY;
459 
460 	if (fImageFunctionsView->SaveSettings(archive) != B_OK)
461 		return B_NO_MEMORY;
462 	if (teamWindowSettings.AddMessage("imageFunctionsView", &archive))
463 		return B_NO_MEMORY;
464 
465 	if (fThreadListView->SaveSettings(archive) != B_OK)
466 		return B_NO_MEMORY;
467 	if (teamWindowSettings.AddMessage("threadListView", &archive))
468 		return B_NO_MEMORY;
469 
470 	if (fVariablesView->SaveSettings(archive) != B_OK)
471 		return B_NO_MEMORY;
472 	if (teamWindowSettings.AddMessage("variablesView", &archive))
473 		return B_NO_MEMORY;
474 
475 	if (fRegistersView->SaveSettings(archive) != B_OK)
476 		return B_NO_MEMORY;
477 	if (teamWindowSettings.AddMessage("registersView", &archive))
478 		return B_NO_MEMORY;
479 
480 	if (fStackTraceView->SaveSettings(archive) != B_OK)
481 		return B_NO_MEMORY;
482 	if (teamWindowSettings.AddMessage("stackTraceView", &archive))
483 		return B_NO_MEMORY;
484 
485 	if (fBreakpointsView->SaveSettings(archive) != B_OK)
486 		return B_NO_MEMORY;
487 	if (teamWindowSettings.AddMessage("breakpointsView", &archive))
488 		return B_NO_MEMORY;
489 
490 	if (!settings->AddSettings("teamWindow", teamWindowSettings))
491 		return B_NO_MEMORY;
492 
493 	return B_OK;
494 }
495 
496 
497 void
498 TeamWindow::ThreadSelectionChanged(::Thread* thread)
499 {
500 	_SetActiveThread(thread);
501 }
502 
503 
504 void
505 TeamWindow::ImageSelectionChanged(Image* image)
506 {
507 	_SetActiveImage(image);
508 }
509 
510 
511 void
512 TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
513 {
514 	_SetActiveStackFrame(frame);
515 }
516 
517 
518 void
519 TeamWindow::FunctionSelectionChanged(FunctionInstance* function)
520 {
521 	// If the function wasn't already active, it was just selected by the user.
522 	if (function != NULL && function != fActiveFunction)
523 		fActiveSourceObject = ACTIVE_SOURCE_FUNCTION;
524 
525 	_SetActiveFunction(function);
526 }
527 
528 
529 void
530 TeamWindow::BreakpointSelectionChanged(UserBreakpoint* breakpoint)
531 {
532 	_SetActiveBreakpoint(breakpoint);
533 }
534 
535 
536 void
537 TeamWindow::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
538 	bool enabled)
539 {
540 	fListener->SetBreakpointEnabledRequested(breakpoint, enabled);
541 }
542 
543 
544 void
545 TeamWindow::ClearBreakpointRequested(UserBreakpoint* breakpoint)
546 {
547 	fListener->ClearBreakpointRequested(breakpoint);
548 }
549 
550 
551 void
552 TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled)
553 {
554 	fListener->SetBreakpointRequested(address, enabled);
555 }
556 
557 
558 void
559 TeamWindow::ClearBreakpointRequested(target_addr_t address)
560 {
561 	fListener->ClearBreakpointRequested(address);
562 }
563 
564 
565 void
566 TeamWindow::ValueNodeValueRequested(CpuState* cpuState,
567 	ValueNodeContainer* container, ValueNode* valueNode)
568 {
569 	fListener->ValueNodeValueRequested(cpuState, container, valueNode);
570 }
571 
572 
573 void
574 TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event)
575 {
576 	BMessage message(MSG_THREAD_STATE_CHANGED);
577 	message.AddInt32("thread", event.GetThread()->ID());
578 	PostMessage(&message);
579 }
580 
581 
582 void
583 TeamWindow::ThreadCpuStateChanged(const Team::ThreadEvent& event)
584 {
585 	BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
586 	message.AddInt32("thread", event.GetThread()->ID());
587 	PostMessage(&message);
588 }
589 
590 
591 void
592 TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event)
593 {
594 	BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
595 	message.AddInt32("thread", event.GetThread()->ID());
596 	PostMessage(&message);
597 }
598 
599 
600 void
601 TeamWindow::ImageDebugInfoChanged(const Team::ImageEvent& event)
602 {
603 	BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
604 	message.AddInt32("image", event.GetImage()->ID());
605 	PostMessage(&message);
606 }
607 
608 
609 void
610 TeamWindow::UserBreakpointChanged(const Team::UserBreakpointEvent& event)
611 {
612 	BMessage message(MSG_USER_BREAKPOINT_CHANGED);
613 	BReference<UserBreakpoint> breakpointReference(event.GetBreakpoint());
614 	if (message.AddPointer("breakpoint", event.GetBreakpoint()) == B_OK
615 		&& PostMessage(&message) == B_OK) {
616 		breakpointReference.Detach();
617 	}
618 }
619 
620 
621 void
622 TeamWindow::FunctionSourceCodeChanged(Function* function)
623 {
624 	TRACE_GUI("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, "
625 		"state: %d\n", function, function->GetSourceCode(),
626 		function->SourceCodeState());
627 
628 	PostMessage(MSG_FUNCTION_SOURCE_CODE_CHANGED);
629 }
630 
631 
632 void
633 TeamWindow::_Init()
634 {
635 	BScrollView* sourceScrollView;
636 
637 	BLayoutBuilder::Group<>(this, B_VERTICAL)
638 		.Add(fMenuBar = new BMenuBar("Menu"))
639 		.AddSplit(B_VERTICAL, 3.0f)
640 			.GetSplitView(&fFunctionSplitView)
641 			.SetInsets(4.0f, 4.0f, 4.0f, 4.0f)
642 			.Add(fTabView = new BTabView("tab view"), 0.4f)
643 			.AddGroup(B_VERTICAL, 4.0f)
644 				.AddGroup(B_HORIZONTAL, 4.0f)
645 					.Add(fRunButton = new BButton("Run"))
646 					.Add(fStepOverButton = new BButton("Step Over"))
647 					.Add(fStepIntoButton = new BButton("Step Into"))
648 					.Add(fStepOutButton = new BButton("Step Out"))
649 					.AddGlue()
650 				.End()
651 				.Add(fSourcePathView = new BStringView(
652 					"source path",
653 					"Source path unavailable."), 4.0f)
654 				.AddSplit(B_HORIZONTAL, 3.0f)
655 					.GetSplitView(&fSourceSplitView)
656 					.Add(sourceScrollView = new BScrollView("source scroll",
657 						NULL, 0, true, true), 3.0f)
658 					.Add(fLocalsTabView = new BTabView("locals view"))
659 				.End()
660 			.End()
661 		.End();
662 
663 	// add source view
664 	sourceScrollView->SetTarget(fSourceView = SourceView::Create(fTeam, this));
665 
666 	// add threads tab
667 	BSplitView* threadGroup = new BSplitView(B_HORIZONTAL);
668 	threadGroup->SetName("Threads");
669 	fTabView->AddTab(threadGroup);
670 	BLayoutBuilder::Split<>(threadGroup)
671 		.GetSplitView(&fThreadSplitView)
672 		.Add(fThreadListView = ThreadListView::Create(fTeam, this))
673 		.Add(fStackTraceView = StackTraceView::Create(this));
674 
675 	// add images tab
676 	BSplitView* imagesGroup = new BSplitView(B_HORIZONTAL);
677 	imagesGroup->SetName("Images");
678 	fTabView->AddTab(imagesGroup);
679 	BLayoutBuilder::Split<>(imagesGroup)
680 		.GetSplitView(&fImageSplitView)
681 		.Add(fImageListView = ImageListView::Create(fTeam, this))
682 		.Add(fImageFunctionsView = ImageFunctionsView::Create(this));
683 
684 	// add breakpoints tab
685 	BGroupView* breakpointsGroup = new BGroupView(B_HORIZONTAL, 4.0f);
686 	breakpointsGroup->SetName("Breakpoints");
687 	fTabView->AddTab(breakpointsGroup);
688 	BLayoutBuilder::Group<>(breakpointsGroup)
689 		.SetInsets(4.0f, 4.0f, 4.0f, 4.0f)
690 		.Add(fBreakpointsView = BreakpointsView::Create(fTeam, this));
691 
692 	// add local variables tab
693 	BView* tab = fVariablesView = VariablesView::Create(this);
694 	fLocalsTabView->AddTab(tab);
695 
696 	// add registers tab
697 	tab = fRegistersView = RegistersView::Create(fTeam->GetArchitecture());
698 	fLocalsTabView->AddTab(tab);
699 
700 	fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
701 	fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER));
702 	fStepIntoButton->SetMessage(new BMessage(MSG_THREAD_STEP_INTO));
703 	fStepOutButton->SetMessage(new BMessage(MSG_THREAD_STEP_OUT));
704 	fRunButton->SetTarget(this);
705 	fStepOverButton->SetTarget(this);
706 	fStepIntoButton->SetTarget(this);
707 	fStepOutButton->SetTarget(this);
708 
709 	fSourcePathView->SetExplicitMinSize(BSize(100.0, B_SIZE_UNSET));
710 	fSourcePathView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
711 	BMessageFilter* filter = new(std::nothrow) PathViewMessageFilter(
712 		BMessenger(this));
713 	if (filter != NULL)
714 		fSourcePathView->AddFilter(filter);
715 
716 	// add menus and menu items
717 	BMenu* menu = new BMenu("File");
718 	fMenuBar->AddItem(menu);
719 	BMenuItem* item = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED),
720 		'Q');
721 	menu->AddItem(item);
722 	item->SetTarget(this);
723 	menu = new BMenu("Edit");
724 	fMenuBar->AddItem(menu);
725 	item = new BMenuItem("Copy", new BMessage(B_COPY), 'C');
726 	menu->AddItem(item);
727 	item->SetTarget(this);
728 	item = new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A');
729 	menu->AddItem(item);
730 	item->SetTarget(this);
731 	menu = new BMenu("Tools");
732 	fMenuBar->AddItem(menu);
733 	item = new BMenuItem("Inspect Memory",
734 		new BMessage(MSG_SHOW_INSPECTOR_WINDOW), 'I');
735 	menu->AddItem(item);
736 	item->SetTarget(this);
737 
738 	AutoLocker< ::Team> locker(fTeam);
739 	_UpdateRunButtons();
740 }
741 
742 
743 void
744 TeamWindow::_SetActiveThread(::Thread* thread)
745 {
746 	if (thread == fActiveThread)
747 		return;
748 
749 	if (fActiveThread != NULL)
750 		fActiveThread->ReleaseReference();
751 
752 	fActiveThread = thread;
753 
754 	if (fActiveThread != NULL)
755 		fActiveThread->AcquireReference();
756 
757 	AutoLocker< ::Team> locker(fTeam);
758 	_UpdateRunButtons();
759 
760 	StackTrace* stackTrace = fActiveThread != NULL
761 		? fActiveThread->GetStackTrace() : NULL;
762 	BReference<StackTrace> stackTraceReference(stackTrace);
763 		// hold a reference until we've set it
764 
765 	locker.Unlock();
766 
767 	fThreadListView->SetThread(fActiveThread);
768 
769 	_SetActiveStackTrace(stackTrace);
770 	_UpdateCpuState();
771 }
772 
773 
774 void
775 TeamWindow::_SetActiveImage(Image* image)
776 {
777 	if (image == fActiveImage)
778 		return;
779 
780 	if (fActiveImage != NULL)
781 		fActiveImage->ReleaseReference();
782 
783 	fActiveImage = image;
784 
785 	AutoLocker< ::Team> locker(fTeam);
786 
787 	ImageDebugInfo* imageDebugInfo = NULL;
788 	BReference<ImageDebugInfo> imageDebugInfoReference;
789 
790 	if (fActiveImage != NULL) {
791 		fActiveImage->AcquireReference();
792 
793 		imageDebugInfo = fActiveImage->GetImageDebugInfo();
794 		imageDebugInfoReference.SetTo(imageDebugInfo);
795 
796 		// If the debug info is not loaded yet, request it.
797 		if (fActiveImage->ImageDebugInfoState() == IMAGE_DEBUG_INFO_NOT_LOADED)
798 			fListener->ImageDebugInfoRequested(fActiveImage);
799 	}
800 
801 	locker.Unlock();
802 
803 	fImageListView->SetImage(fActiveImage);
804 	fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
805 }
806 
807 
808 void
809 TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace)
810 {
811 	if (stackTrace == fActiveStackTrace)
812 		return;
813 
814 	if (fActiveStackTrace != NULL)
815 		fActiveStackTrace->ReleaseReference();
816 
817 	fActiveStackTrace = stackTrace;
818 
819 	if (fActiveStackTrace != NULL)
820 		fActiveStackTrace->AcquireReference();
821 
822 	fStackTraceView->SetStackTrace(fActiveStackTrace);
823 	fSourceView->SetStackTrace(fActiveStackTrace);
824 
825 	if (fActiveStackTrace != NULL)
826 		_SetActiveStackFrame(fActiveStackTrace->FrameAt(0));
827 }
828 
829 
830 void
831 TeamWindow::_SetActiveStackFrame(StackFrame* frame)
832 {
833 	if (frame == fActiveStackFrame)
834 		return;
835 
836 	if (fActiveStackFrame != NULL) {
837 		AutoLocker< ::Team> locker(fTeam);
838 		fActiveStackFrame->RemoveListener(this);
839 		locker.Unlock();
840 
841 		fActiveStackFrame->ReleaseReference();
842 	}
843 
844 	fActiveStackFrame = frame;
845 
846 	if (fActiveStackFrame != NULL) {
847 		fActiveStackFrame->AcquireReference();
848 
849 		AutoLocker< ::Team> locker(fTeam);
850 		fActiveStackFrame->AddListener(this);
851 		locker.Unlock();
852 
853 		fActiveSourceObject = ACTIVE_SOURCE_STACK_FRAME;
854 
855 		_SetActiveFunction(fActiveStackFrame->Function());
856 	}
857 
858 	_UpdateCpuState();
859 
860 	fStackTraceView->SetStackFrame(fActiveStackFrame);
861 	if (fActiveStackFrame != NULL)
862 		fVariablesView->SetStackFrame(fActiveThread, fActiveStackFrame);
863 	else
864 		fVariablesView->SetStackFrame(NULL, NULL);
865 	fSourceView->SetStackFrame(fActiveStackFrame);
866 }
867 
868 
869 void
870 TeamWindow::_SetActiveBreakpoint(UserBreakpoint* breakpoint)
871 {
872 	if (breakpoint == fActiveBreakpoint)
873 		return;
874 
875 	if (fActiveBreakpoint != NULL)
876 		fActiveBreakpoint->ReleaseReference();
877 
878 	fActiveBreakpoint = breakpoint;
879 
880 	if (fActiveBreakpoint != NULL) {
881 		fActiveBreakpoint->AcquireReference();
882 
883 		// get the breakpoint's function (more exactly: some function instance)
884 		AutoLocker< ::Team> locker(fTeam);
885 
886 		Function* function = fTeam->FunctionByID(
887 			breakpoint->Location().GetFunctionID());
888 		FunctionInstance* functionInstance = function != NULL
889 			? function->FirstInstance() : NULL;
890 		BReference<FunctionInstance> functionInstanceReference(
891 			functionInstance);
892 
893 		locker.Unlock();
894 
895 		fActiveSourceObject = ACTIVE_SOURCE_BREAKPOINT;
896 
897 		_SetActiveFunction(functionInstance);
898 
899 		// scroll to the breakpoint's source code line number (it is not done
900 		// automatically, if the active function remains the same)
901 		_ScrollToActiveFunction();
902 	}
903 
904 	fBreakpointsView->SetBreakpoint(fActiveBreakpoint);
905 }
906 
907 
908 void
909 TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance)
910 {
911 	if (functionInstance == fActiveFunction)
912 		return;
913 
914 	AutoLocker< ::Team> locker(fTeam);
915 
916 	if (fActiveFunction != NULL) {
917 		fActiveFunction->GetFunction()->RemoveListener(this);
918 		fActiveFunction->ReleaseReference();
919 	}
920 
921 	// to avoid listener feedback problems, first unset the active function and
922 	// set the new image, if any
923 	locker.Unlock();
924 
925 	fActiveFunction = NULL;
926 
927 	if (functionInstance != NULL)
928 		_SetActiveImage(fTeam->ImageByAddress(functionInstance->Address()));
929 
930 	fActiveFunction = functionInstance;
931 
932 	locker.Lock();
933 
934 	SourceCode* sourceCode = NULL;
935 	BReference<SourceCode> sourceCodeReference;
936 
937 	if (fActiveFunction != NULL) {
938 		fActiveFunction->AcquireReference();
939 		fActiveFunction->GetFunction()->AddListener(this);
940 
941 		Function* function = fActiveFunction->GetFunction();
942 		sourceCode = function->GetSourceCode();
943 		if (sourceCode == NULL)
944 			sourceCode = fActiveFunction->GetSourceCode();
945 		sourceCodeReference.SetTo(sourceCode);
946 
947 		// If the source code is not loaded yet, request it.
948 		if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED)
949 			fListener->FunctionSourceCodeRequested(fActiveFunction);
950 	}
951 
952 	locker.Unlock();
953 
954 	_SetActiveSourceCode(sourceCode);
955 
956 	fImageFunctionsView->SetFunction(fActiveFunction);
957 
958 	locker.Lock();
959 
960 	// look if our current stack trace has a frame matching the selected
961 	// function. If so, set it to match.
962 	StackFrame* matchingFrame = NULL;
963 	BReference<StackFrame> frameRef;
964 
965 	if (fActiveStackTrace != NULL) {
966 		for (int32 i = 0; i < fActiveStackTrace->CountFrames(); i++) {
967 			StackFrame* frame = fActiveStackTrace->FrameAt(i);
968 			if (frame->Function() == fActiveFunction) {
969 				matchingFrame = frame;
970 				frameRef.SetTo(frame);
971 				break;
972 			}
973 		}
974 	}
975 
976 	locker.Unlock();
977 
978 	if (matchingFrame != NULL)
979 		_SetActiveStackFrame(matchingFrame);
980 }
981 
982 
983 void
984 TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
985 {
986 	if (sourceCode == fActiveSourceCode) {
987 		_ScrollToActiveFunction();
988 		return;
989 	}
990 
991 	if (fActiveSourceCode != NULL)
992 		fActiveSourceCode->ReleaseReference();
993 
994 	fActiveSourceCode = sourceCode;
995 
996 	if (fActiveSourceCode != NULL)
997 		fActiveSourceCode->AcquireReference();
998 
999 	fSourceView->SetSourceCode(fActiveSourceCode);
1000 
1001 	_UpdateSourcePathState();
1002 	_ScrollToActiveFunction();
1003 }
1004 
1005 void
1006 TeamWindow::_UpdateCpuState()
1007 {
1008 	// get the CPU state
1009 	CpuState* cpuState = NULL;
1010 	BReference<CpuState> cpuStateReference;
1011 		// hold a reference until the register view has one
1012 
1013 	if (fActiveThread != NULL) {
1014 		// Get the CPU state from the active stack frame or the thread directly.
1015 		if (fActiveStackFrame == NULL) {
1016 			AutoLocker< ::Team> locker(fTeam);
1017 			cpuState = fActiveThread->GetCpuState();
1018 			cpuStateReference.SetTo(cpuState);
1019 			locker.Unlock();
1020 		} else
1021 			cpuState = fActiveStackFrame->GetCpuState();
1022 	}
1023 
1024 	fRegistersView->SetCpuState(cpuState);
1025 }
1026 
1027 
1028 void
1029 TeamWindow::_UpdateRunButtons()
1030 {
1031 	uint32 threadState = fActiveThread != NULL
1032 		? fActiveThread->State() : THREAD_STATE_UNKNOWN;
1033 
1034 	switch (threadState) {
1035 		case THREAD_STATE_UNKNOWN:
1036 			fRunButton->SetEnabled(false);
1037 			fStepOverButton->SetEnabled(false);
1038 			fStepIntoButton->SetEnabled(false);
1039 			fStepOutButton->SetEnabled(false);
1040 			break;
1041 		case THREAD_STATE_RUNNING:
1042 			fRunButton->SetLabel("Debug");
1043 			fRunButton->SetMessage(new BMessage(MSG_THREAD_STOP));
1044 			fRunButton->SetEnabled(true);
1045 			fStepOverButton->SetEnabled(false);
1046 			fStepIntoButton->SetEnabled(false);
1047 			fStepOutButton->SetEnabled(false);
1048 			break;
1049 		case THREAD_STATE_STOPPED:
1050 			fRunButton->SetLabel("Run");
1051 			fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
1052 			fRunButton->SetEnabled(true);
1053 			fStepOverButton->SetEnabled(true);
1054 			fStepIntoButton->SetEnabled(true);
1055 			fStepOutButton->SetEnabled(true);
1056 			break;
1057 	}
1058 }
1059 
1060 
1061 void
1062 TeamWindow::_UpdateSourcePathState()
1063 {
1064 	LocatableFile* sourceFile = NULL;
1065 	BString sourceText = "Source file unavailable.";
1066 	BString truncatedText;
1067 
1068 	if (fActiveSourceCode != NULL) {
1069 		sourceFile = fActiveFunction->GetFunctionDebugInfo()->SourceFile();
1070 
1071 		if (sourceFile != NULL && !sourceFile->GetLocatedPath(sourceText))
1072 			sourceFile->GetPath(sourceText);
1073 
1074 		if (fActiveSourceCode->GetSourceFile() == NULL && sourceFile != NULL) {
1075 			sourceText.Prepend("Click to locate source file '");
1076 			sourceText += "'";
1077 			truncatedText = sourceText;
1078 			fSourcePathView->TruncateString(&truncatedText, B_TRUNCATE_MIDDLE,
1079 				fSourcePathView->Bounds().Width());
1080 		} else if (sourceFile != NULL) {
1081 			sourceText.Prepend("File: ");
1082 		}
1083 	}
1084 
1085 	if (!truncatedText.IsEmpty() && truncatedText != sourceText) {
1086 		fSourcePathView->SetToolTip(sourceText);
1087 		fSourcePathView->SetText(truncatedText);
1088 	} else
1089 		fSourcePathView->SetText(sourceText);
1090 }
1091 
1092 
1093 void
1094 TeamWindow::_ScrollToActiveFunction()
1095 {
1096 	// Scroll to the active function, if it has been selected manually.
1097 	if (fActiveFunction == NULL || fActiveSourceCode == NULL)
1098 		return;
1099 
1100 	switch (fActiveSourceObject) {
1101 		case ACTIVE_SOURCE_FUNCTION:
1102 			fSourceView->ScrollToAddress(fActiveFunction->Address());
1103 			break;
1104 		case ACTIVE_SOURCE_BREAKPOINT:
1105 		{
1106 			if (fActiveBreakpoint == NULL)
1107 				break;
1108 
1109 			const UserBreakpointLocation& location
1110 				= fActiveBreakpoint->Location();
1111 			int32 line = location.GetSourceLocation().Line();
1112 
1113 			if (location.SourceFile() != NULL && line >= 0
1114 				&& fActiveSourceCode->GetSourceFile()
1115 					== location.SourceFile()) {
1116 				fSourceView->ScrollToLine(line);
1117 			} else {
1118 				fSourceView->ScrollToAddress(
1119 					fActiveFunction->Address()
1120 						+ location.RelativeAddress());
1121 			}
1122 			break;
1123 		}
1124 		case ACTIVE_SOURCE_NONE:
1125 		case ACTIVE_SOURCE_STACK_FRAME:
1126 			break;
1127 	}
1128 }
1129 
1130 
1131 void
1132 TeamWindow::_HandleThreadStateChanged(thread_id threadID)
1133 {
1134 	AutoLocker< ::Team> locker(fTeam);
1135 
1136 	::Thread* thread = fTeam->ThreadByID(threadID);
1137 	if (thread == NULL)
1138 		return;
1139 
1140 	// If the thread has been stopped and we don't have an active thread yet
1141 	// (or it isn't stopped), switch to this thread. Otherwise ignore the event.
1142 	if (thread->State() == THREAD_STATE_STOPPED
1143 		&& (fActiveThread == NULL
1144 			|| (thread != fActiveThread
1145 				&& fActiveThread->State() != THREAD_STATE_STOPPED))) {
1146 		_SetActiveThread(thread);
1147 	} else if (thread != fActiveThread) {
1148 		// otherwise ignore the event, if the thread is not the active one
1149 		return;
1150 	}
1151 
1152 	// Switch to the threads tab view when the thread has stopped.
1153 	if (thread->State() == THREAD_STATE_STOPPED)
1154 		fTabView->Select(MAIN_TAB_INDEX_THREADS);
1155 
1156 	_UpdateRunButtons();
1157 }
1158 
1159 
1160 void
1161 TeamWindow::_HandleCpuStateChanged(thread_id threadID)
1162 {
1163 	// We're only interested in the currently selected thread
1164 	if (fActiveThread == NULL || threadID != fActiveThread->ID())
1165 		return;
1166 
1167 	_UpdateCpuState();
1168 }
1169 
1170 
1171 void
1172 TeamWindow::_HandleStackTraceChanged(thread_id threadID)
1173 {
1174 	// We're only interested in the currently selected thread
1175 	if (fActiveThread == NULL || threadID != fActiveThread->ID())
1176 		return;
1177 
1178 	AutoLocker< ::Team> locker(fTeam);
1179 
1180 	StackTrace* stackTrace = fActiveThread != NULL
1181 		? fActiveThread->GetStackTrace() : NULL;
1182 	BReference<StackTrace> stackTraceReference(stackTrace);
1183 		// hold a reference until the register view has one
1184 
1185 	locker.Unlock();
1186 
1187 	_SetActiveStackTrace(stackTrace);
1188 }
1189 
1190 
1191 void
1192 TeamWindow::_HandleImageDebugInfoChanged(image_id imageID)
1193 {
1194 	TRACE_GUI("TeamWindow::_HandleImageDebugInfoChanged(%ld)\n", imageID);
1195 
1196 	// We're only interested in the currently selected thread
1197 	if (fActiveImage == NULL || imageID != fActiveImage->ID())
1198 		return;
1199 
1200 	AutoLocker< ::Team> locker(fTeam);
1201 
1202 	ImageDebugInfo* imageDebugInfo = fActiveImage != NULL
1203 		? fActiveImage->GetImageDebugInfo() : NULL;
1204 
1205 	TRACE_GUI("  image debug info: %p\n", imageDebugInfo);
1206 
1207 	BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo);
1208 		// hold a reference until we've set it
1209 
1210 	locker.Unlock();
1211 
1212 	fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
1213 }
1214 
1215 
1216 void
1217 TeamWindow::_HandleSourceCodeChanged()
1218 {
1219 	// If we don't have an active function anymore, the message is obsolete.
1220 	if (fActiveFunction == NULL)
1221 		return;
1222 
1223 	// get a reference to the source code
1224 	AutoLocker< ::Team> locker(fTeam);
1225 
1226 	SourceCode* sourceCode = fActiveFunction->GetFunction()->GetSourceCode();
1227 	if (sourceCode == NULL)
1228 		sourceCode = fActiveFunction->GetSourceCode();
1229 
1230 	BReference<SourceCode> sourceCodeReference(sourceCode);
1231 
1232 	locker.Unlock();
1233 
1234 	_SetActiveSourceCode(sourceCode);
1235 }
1236 
1237 
1238 void
1239 TeamWindow::_HandleUserBreakpointChanged(UserBreakpoint* breakpoint)
1240 {
1241 	fSourceView->UserBreakpointChanged(breakpoint);
1242 	fBreakpointsView->UserBreakpointChanged(breakpoint);
1243 }
1244 
1245 
1246 void
1247 TeamWindow::_HandleResolveMissingSourceFile(entry_ref& locatedPath)
1248 {
1249 	if (fActiveFunction != NULL) {
1250 		LocatableFile* sourceFile = fActiveFunction->GetFunctionDebugInfo()
1251 			->SourceFile();
1252 		if (sourceFile != NULL) {
1253 			BString sourcePath;
1254 			BString targetPath;
1255 			sourceFile->GetPath(sourcePath);
1256 			BPath path(&locatedPath);
1257 			targetPath = path.Path();
1258 			fListener->SourceEntryLocateRequested(sourcePath, targetPath);
1259 			fListener->FunctionSourceCodeRequested(fActiveFunction);
1260 		}
1261 	}
1262 }
1263 
1264 
1265 status_t
1266 TeamWindow::_SaveInspectorSettings(const BMessage* settings)
1267 {
1268 	if (fUiSettings.AddSettings("inspectorWindow", *settings) != B_OK)
1269 		return B_NO_MEMORY;
1270 
1271 	return B_OK;
1272 }
1273