xref: /haiku/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp (revision b46615c55ad2c8fe6de54412055a0713da3d610a)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2010, 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 "Image.h"
34 #include "ImageDebugInfo.h"
35 #include "LocatableFile.h"
36 #include "MessageCodes.h"
37 #include "RegistersView.h"
38 #include "StackTrace.h"
39 #include "StackTraceView.h"
40 #include "Tracing.h"
41 #include "TypeComponentPath.h"
42 #include "UserInterface.h"
43 #include "Variable.h"
44 
45 
46 enum {
47 	MAIN_TAB_INDEX_THREADS	= 0,
48 	MAIN_TAB_INDEX_IMAGES	= 1
49 };
50 
51 
52 enum {
53 	MSG_LOCATE_SOURCE_IF_NEEDED = 'lsin'
54 };
55 
56 
57 class PathViewMessageFilter : public BMessageFilter {
58 public:
59 		PathViewMessageFilter(BMessenger teamWindow)
60 			:
61 			BMessageFilter(B_MOUSE_UP),
62 			fTeamWindowMessenger(teamWindow)
63 		{
64 		}
65 
66 		virtual filter_result Filter(BMessage*, BHandler**)
67 		{
68 			fTeamWindowMessenger.SendMessage(MSG_LOCATE_SOURCE_IF_NEEDED);
69 
70 			return B_DISPATCH_MESSAGE;
71 		}
72 
73 private:
74 		BMessenger fTeamWindowMessenger;
75 };
76 
77 
78 // #pragma mark - TeamWindow
79 
80 
81 TeamWindow::TeamWindow(::Team* team, UserInterfaceListener* listener)
82 	:
83 	BWindow(BRect(100, 100, 899, 699), "Team", B_TITLED_WINDOW,
84 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
85 	fTeam(team),
86 	fActiveThread(NULL),
87 	fActiveImage(NULL),
88 	fActiveStackTrace(NULL),
89 	fActiveStackFrame(NULL),
90 	fActiveBreakpoint(NULL),
91 	fActiveFunction(NULL),
92 	fActiveSourceCode(NULL),
93 	fActiveSourceObject(ACTIVE_SOURCE_NONE),
94 	fListener(listener),
95 	fTabView(NULL),
96 	fLocalsTabView(NULL),
97 	fThreadListView(NULL),
98 	fImageListView(NULL),
99 	fImageFunctionsView(NULL),
100 	fBreakpointsView(NULL),
101 	fVariablesView(NULL),
102 	fRegistersView(NULL),
103 	fStackTraceView(NULL),
104 	fSourceView(NULL),
105 	fRunButton(NULL),
106 	fStepOverButton(NULL),
107 	fStepIntoButton(NULL),
108 	fStepOutButton(NULL)
109 {
110 	fTeam->Lock();
111 	BString name = fTeam->Name();
112 	fTeam->Unlock();
113 	if (fTeam->ID() >= 0)
114 		name << " (" << fTeam->ID() << ")";
115 	SetTitle(name.String());
116 
117 	fTeam->AddListener(this);
118 }
119 
120 
121 TeamWindow::~TeamWindow()
122 {
123 	if (fThreadListView != NULL)
124 		fThreadListView->UnsetListener();
125 	if (fStackTraceView != NULL)
126 		fStackTraceView->UnsetListener();
127 	if (fSourceView != NULL)
128 		fSourceView->UnsetListener();
129 
130 	fTeam->RemoveListener(this);
131 
132 	_SetActiveSourceCode(NULL);
133 	_SetActiveFunction(NULL);
134 	_SetActiveBreakpoint(NULL);
135 	_SetActiveStackFrame(NULL);
136 	_SetActiveStackTrace(NULL);
137 	_SetActiveImage(NULL);
138 	_SetActiveThread(NULL);
139 }
140 
141 
142 /*static*/ TeamWindow*
143 TeamWindow::Create(::Team* team, UserInterfaceListener* listener)
144 {
145 	TeamWindow* self = new TeamWindow(team, listener);
146 
147 	try {
148 		self->_Init();
149 	} catch (...) {
150 		delete self;
151 		throw;
152 	}
153 
154 	return self;
155 }
156 
157 
158 void
159 TeamWindow::DispatchMessage(BMessage* message, BHandler* handler)
160 {
161 	// Handle function key shortcuts for stepping
162 	switch (message->what) {
163 		case B_KEY_DOWN:
164 			if (fActiveThread != NULL) {
165 				int32 key;
166 				uint32 modifiers;
167 				if (message->FindInt32("key", &key) == B_OK
168 					&& message->FindInt32("modifiers", (int32*)&modifiers)
169 					== B_OK) {
170 					switch (key) {
171 						case B_F10_KEY:
172 							fListener->ThreadActionRequested(
173 								fActiveThread->ID(), MSG_THREAD_STEP_OVER);
174 							break;
175 						case B_F11_KEY:
176 							if ((modifiers & B_SHIFT_KEY) != 0) {
177 								fListener->ThreadActionRequested(
178 									fActiveThread->ID(), MSG_THREAD_STEP_OUT);
179 							} else {
180 								fListener->ThreadActionRequested(
181 									fActiveThread->ID(), MSG_THREAD_STEP_INTO);
182 							}
183 							break;
184 						default:
185 							break;
186 					}
187 				}
188 			}
189 			break;
190 
191 		case B_COPY:
192 		case B_SELECT_ALL:
193 			BView* focusView = CurrentFocus();
194 			if (focusView != NULL)
195 				focusView->MessageReceived(message);
196 			break;
197 	}
198 	BWindow::DispatchMessage(message, handler);
199 }
200 
201 
202 void
203 TeamWindow::MessageReceived(BMessage* message)
204 {
205 	switch (message->what) {
206 		case B_REFS_RECEIVED:
207 		{
208 			entry_ref locatedPath;
209 			message->FindRef("refs", &locatedPath);
210 			_HandleResolveMissingSourceFile(locatedPath);
211 			break;
212 		}
213 		case MSG_LOCATE_SOURCE_IF_NEEDED:
214 		{
215 			if (fActiveFunction != NULL
216 				&& fActiveFunction->GetFunctionDebugInfo()
217 					->SourceFile() != NULL && fActiveSourceCode != NULL
218 				&& fActiveSourceCode->GetSourceFile() == NULL) {
219 				BFilePanel* panel = NULL;
220 				try {
221 					panel = new BFilePanel(B_OPEN_PANEL,
222 						new BMessenger(this));
223 					panel->Show();
224 				} catch (...) {
225 					delete panel;
226 				}
227 			}
228 			break;
229 		}
230 		case MSG_THREAD_RUN:
231 		case MSG_THREAD_STOP:
232 		case MSG_THREAD_STEP_OVER:
233 		case MSG_THREAD_STEP_INTO:
234 		case MSG_THREAD_STEP_OUT:
235 			if (fActiveThread != NULL) {
236 				fListener->ThreadActionRequested(fActiveThread->ID(),
237 					message->what);
238 			}
239 			break;
240 
241 		case MSG_THREAD_STATE_CHANGED:
242 		{
243 			int32 threadID;
244 			if (message->FindInt32("thread", &threadID) != B_OK)
245 				break;
246 
247 			_HandleThreadStateChanged(threadID);
248 			break;
249 		}
250 		case MSG_THREAD_CPU_STATE_CHANGED:
251 		{
252 			int32 threadID;
253 			if (message->FindInt32("thread", &threadID) != B_OK)
254 				break;
255 
256 			_HandleCpuStateChanged(threadID);
257 			break;
258 		}
259 
260 		case MSG_THREAD_STACK_TRACE_CHANGED:
261 		{
262 			int32 threadID;
263 			if (message->FindInt32("thread", &threadID) != B_OK)
264 				break;
265 
266 			_HandleStackTraceChanged(threadID);
267 			break;
268 		}
269 
270 		case MSG_IMAGE_DEBUG_INFO_CHANGED:
271 		{
272 			int32 imageID;
273 			if (message->FindInt32("image", &imageID) != B_OK)
274 				break;
275 
276 			_HandleImageDebugInfoChanged(imageID);
277 			break;
278 		}
279 
280 		case MSG_USER_BREAKPOINT_CHANGED:
281 		{
282 			UserBreakpoint* breakpoint;
283 			if (message->FindPointer("breakpoint", (void**)&breakpoint) != B_OK)
284 				break;
285 			BReference<UserBreakpoint> breakpointReference(breakpoint, true);
286 
287 			_HandleUserBreakpointChanged(breakpoint);
288 			break;
289 		}
290 
291 		case MSG_FUNCTION_SOURCE_CODE_CHANGED:
292 		{
293 			_HandleSourceCodeChanged();
294 			break;
295 		}
296 
297 		default:
298 			BWindow::MessageReceived(message);
299 			break;
300 	}
301 }
302 
303 
304 bool
305 TeamWindow::QuitRequested()
306 {
307 	return fListener->UserInterfaceQuitRequested();
308 }
309 
310 
311 void
312 TeamWindow::ThreadSelectionChanged(::Thread* thread)
313 {
314 	_SetActiveThread(thread);
315 }
316 
317 
318 void
319 TeamWindow::ImageSelectionChanged(Image* image)
320 {
321 	_SetActiveImage(image);
322 }
323 
324 
325 void
326 TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
327 {
328 	_SetActiveStackFrame(frame);
329 }
330 
331 
332 void
333 TeamWindow::FunctionSelectionChanged(FunctionInstance* function)
334 {
335 	// If the function wasn't already active, it was just selected by the user.
336 	if (function != NULL && function != fActiveFunction)
337 		fActiveSourceObject = ACTIVE_SOURCE_FUNCTION;
338 
339 	_SetActiveFunction(function);
340 }
341 
342 
343 void
344 TeamWindow::BreakpointSelectionChanged(UserBreakpoint* breakpoint)
345 {
346 	_SetActiveBreakpoint(breakpoint);
347 }
348 
349 
350 void
351 TeamWindow::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
352 	bool enabled)
353 {
354 	fListener->SetBreakpointEnabledRequested(breakpoint, enabled);
355 }
356 
357 
358 void
359 TeamWindow::ClearBreakpointRequested(UserBreakpoint* breakpoint)
360 {
361 	fListener->ClearBreakpointRequested(breakpoint);
362 }
363 
364 
365 void
366 TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled)
367 {
368 	fListener->SetBreakpointRequested(address, enabled);
369 }
370 
371 
372 void
373 TeamWindow::ClearBreakpointRequested(target_addr_t address)
374 {
375 	fListener->ClearBreakpointRequested(address);
376 }
377 
378 
379 void
380 TeamWindow::ValueNodeValueRequested(CpuState* cpuState,
381 	ValueNodeContainer* container, ValueNode* valueNode)
382 {
383 	fListener->ValueNodeValueRequested(cpuState, container, valueNode);
384 }
385 
386 
387 void
388 TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event)
389 {
390 	BMessage message(MSG_THREAD_STATE_CHANGED);
391 	message.AddInt32("thread", event.GetThread()->ID());
392 	PostMessage(&message);
393 }
394 
395 
396 void
397 TeamWindow::ThreadCpuStateChanged(const Team::ThreadEvent& event)
398 {
399 	BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
400 	message.AddInt32("thread", event.GetThread()->ID());
401 	PostMessage(&message);
402 }
403 
404 
405 void
406 TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event)
407 {
408 	BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
409 	message.AddInt32("thread", event.GetThread()->ID());
410 	PostMessage(&message);
411 }
412 
413 
414 void
415 TeamWindow::ImageDebugInfoChanged(const Team::ImageEvent& event)
416 {
417 	BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
418 	message.AddInt32("image", event.GetImage()->ID());
419 	PostMessage(&message);
420 }
421 
422 
423 void
424 TeamWindow::UserBreakpointChanged(const Team::UserBreakpointEvent& event)
425 {
426 	BMessage message(MSG_USER_BREAKPOINT_CHANGED);
427 	BReference<UserBreakpoint> breakpointReference(event.GetBreakpoint());
428 	if (message.AddPointer("breakpoint", event.GetBreakpoint()) == B_OK
429 		&& PostMessage(&message) == B_OK) {
430 		breakpointReference.Detach();
431 	}
432 }
433 
434 
435 void
436 TeamWindow::FunctionSourceCodeChanged(Function* function)
437 {
438 	TRACE_GUI("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, "
439 		"state: %d\n", function, function->GetSourceCode(),
440 		function->SourceCodeState());
441 
442 	PostMessage(MSG_FUNCTION_SOURCE_CODE_CHANGED);
443 }
444 
445 
446 void
447 TeamWindow::_Init()
448 {
449 	BScrollView* sourceScrollView;
450 
451 	BLayoutBuilder::Group<>(this, B_VERTICAL)
452 		.Add(fMenuBar = new BMenuBar("Menu"))
453 		.AddSplit(B_VERTICAL, 3.0f)
454 			.SetInsets(4.0f, 4.0f, 4.0f, 4.0f)
455 			.Add(fTabView = new BTabView("tab view"), 0.4f)
456 			.AddGroup(B_VERTICAL, 4.0f)
457 				.AddGroup(B_HORIZONTAL, 4.0f)
458 					.Add(fRunButton = new BButton("Run"))
459 					.Add(fStepOverButton = new BButton("Step Over"))
460 					.Add(fStepIntoButton = new BButton("Step Into"))
461 					.Add(fStepOutButton = new BButton("Step Out"))
462 					.AddGlue()
463 				.End()
464 				.Add(fSourcePathView = new BStringView(
465 					"source path",
466 					"Source path unavailable."), 4.0f)
467 				.AddSplit(B_HORIZONTAL, 3.0f)
468 					.Add(sourceScrollView = new BScrollView("source scroll",
469 						NULL, 0, true, true), 3.0f)
470 					.Add(fLocalsTabView = new BTabView("locals view"))
471 				.End()
472 			.End()
473 		.End();
474 
475 	// add source view
476 	sourceScrollView->SetTarget(fSourceView = SourceView::Create(fTeam, this));
477 
478 	// add threads tab
479 	BSplitView* threadGroup = new BSplitView(B_HORIZONTAL);
480 	threadGroup->SetName("Threads");
481 	fTabView->AddTab(threadGroup);
482 	BLayoutBuilder::Split<>(threadGroup)
483 		.Add(fThreadListView = ThreadListView::Create(fTeam, this))
484 		.Add(fStackTraceView = StackTraceView::Create(this));
485 
486 	// add images tab
487 	BSplitView* imagesGroup = new BSplitView(B_HORIZONTAL);
488 	imagesGroup->SetName("Images");
489 	fTabView->AddTab(imagesGroup);
490 	BLayoutBuilder::Split<>(imagesGroup)
491 		.Add(fImageListView = ImageListView::Create(fTeam, this))
492 		.Add(fImageFunctionsView = ImageFunctionsView::Create(this));
493 
494 	// add breakpoints tab
495 	BGroupView* breakpointsGroup = new BGroupView(B_HORIZONTAL, 4.0f);
496 	breakpointsGroup->SetName("Breakpoints");
497 	fTabView->AddTab(breakpointsGroup);
498 	BLayoutBuilder::Group<>(breakpointsGroup)
499 		.SetInsets(4.0f, 4.0f, 4.0f, 4.0f)
500 		.Add(fBreakpointsView = BreakpointsView::Create(fTeam, this));
501 
502 	// add local variables tab
503 	BView* tab = fVariablesView = VariablesView::Create(this);
504 	fLocalsTabView->AddTab(tab);
505 
506 	// add registers tab
507 	tab = fRegistersView = RegistersView::Create(fTeam->GetArchitecture());
508 	fLocalsTabView->AddTab(tab);
509 
510 	fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
511 	fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER));
512 	fStepIntoButton->SetMessage(new BMessage(MSG_THREAD_STEP_INTO));
513 	fStepOutButton->SetMessage(new BMessage(MSG_THREAD_STEP_OUT));
514 	fRunButton->SetTarget(this);
515 	fStepOverButton->SetTarget(this);
516 	fStepIntoButton->SetTarget(this);
517 	fStepOutButton->SetTarget(this);
518 
519 	fSourcePathView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
520 	BMessageFilter* filter = new(std::nothrow) PathViewMessageFilter(
521 		BMessenger(this));
522 	if (filter != NULL)
523 		fSourcePathView->AddFilter(filter);
524 
525 	// add menus and menu items
526 	BMenu* menu = new BMenu("File");
527 	fMenuBar->AddItem(menu);
528 	BMenuItem* item = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED),
529 		'Q');
530 	menu->AddItem(item);
531 	item->SetTarget(this);
532 	menu = new BMenu("Edit");
533 	fMenuBar->AddItem(menu);
534 	item = new BMenuItem("Copy", new BMessage(B_COPY), 'C');
535 	menu->AddItem(item);
536 	item->SetTarget(this);
537 	item = new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A');
538 	menu->AddItem(item);
539 	item->SetTarget(this);
540 
541 	AutoLocker< ::Team> locker(fTeam);
542 	_UpdateRunButtons();
543 }
544 
545 
546 void
547 TeamWindow::_SetActiveThread(::Thread* thread)
548 {
549 	if (thread == fActiveThread)
550 		return;
551 
552 	if (fActiveThread != NULL)
553 		fActiveThread->ReleaseReference();
554 
555 	fActiveThread = thread;
556 
557 	if (fActiveThread != NULL)
558 		fActiveThread->AcquireReference();
559 
560 	AutoLocker< ::Team> locker(fTeam);
561 	_UpdateRunButtons();
562 
563 	StackTrace* stackTrace = fActiveThread != NULL
564 		? fActiveThread->GetStackTrace() : NULL;
565 	BReference<StackTrace> stackTraceReference(stackTrace);
566 		// hold a reference until we've set it
567 
568 	locker.Unlock();
569 
570 	fThreadListView->SetThread(fActiveThread);
571 
572 	_SetActiveStackTrace(stackTrace);
573 	_UpdateCpuState();
574 }
575 
576 
577 void
578 TeamWindow::_SetActiveImage(Image* image)
579 {
580 	if (image == fActiveImage)
581 		return;
582 
583 	if (fActiveImage != NULL)
584 		fActiveImage->ReleaseReference();
585 
586 	fActiveImage = image;
587 
588 	AutoLocker< ::Team> locker(fTeam);
589 
590 	ImageDebugInfo* imageDebugInfo = NULL;
591 	BReference<ImageDebugInfo> imageDebugInfoReference;
592 
593 	if (fActiveImage != NULL) {
594 		fActiveImage->AcquireReference();
595 
596 		imageDebugInfo = fActiveImage->GetImageDebugInfo();
597 		imageDebugInfoReference.SetTo(imageDebugInfo);
598 
599 		// If the debug info is not loaded yet, request it.
600 		if (fActiveImage->ImageDebugInfoState() == IMAGE_DEBUG_INFO_NOT_LOADED)
601 			fListener->ImageDebugInfoRequested(fActiveImage);
602 	}
603 
604 	locker.Unlock();
605 
606 	fImageListView->SetImage(fActiveImage);
607 	fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
608 }
609 
610 
611 void
612 TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace)
613 {
614 	if (stackTrace == fActiveStackTrace)
615 		return;
616 
617 	if (fActiveStackTrace != NULL)
618 		fActiveStackTrace->ReleaseReference();
619 
620 	fActiveStackTrace = stackTrace;
621 
622 	if (fActiveStackTrace != NULL)
623 		fActiveStackTrace->AcquireReference();
624 
625 	fStackTraceView->SetStackTrace(fActiveStackTrace);
626 	fSourceView->SetStackTrace(fActiveStackTrace);
627 
628 	if (fActiveStackTrace != NULL)
629 		_SetActiveStackFrame(fActiveStackTrace->FrameAt(0));
630 }
631 
632 
633 void
634 TeamWindow::_SetActiveStackFrame(StackFrame* frame)
635 {
636 	if (frame == fActiveStackFrame)
637 		return;
638 
639 	if (fActiveStackFrame != NULL) {
640 		AutoLocker< ::Team> locker(fTeam);
641 		fActiveStackFrame->RemoveListener(this);
642 		locker.Unlock();
643 
644 		fActiveStackFrame->ReleaseReference();
645 	}
646 
647 	fActiveStackFrame = frame;
648 
649 	if (fActiveStackFrame != NULL) {
650 		fActiveStackFrame->AcquireReference();
651 
652 		AutoLocker< ::Team> locker(fTeam);
653 		fActiveStackFrame->AddListener(this);
654 		locker.Unlock();
655 
656 		fActiveSourceObject = ACTIVE_SOURCE_STACK_FRAME;
657 
658 		_SetActiveFunction(fActiveStackFrame->Function());
659 	}
660 
661 	_UpdateCpuState();
662 
663 	fStackTraceView->SetStackFrame(fActiveStackFrame);
664 	if (fActiveStackFrame != NULL)
665 		fVariablesView->SetStackFrame(fActiveThread, fActiveStackFrame);
666 	else
667 		fVariablesView->SetStackFrame(NULL, NULL);
668 	fSourceView->SetStackFrame(fActiveStackFrame);
669 }
670 
671 
672 void
673 TeamWindow::_SetActiveBreakpoint(UserBreakpoint* breakpoint)
674 {
675 	if (breakpoint == fActiveBreakpoint)
676 		return;
677 
678 	if (fActiveBreakpoint != NULL)
679 		fActiveBreakpoint->ReleaseReference();
680 
681 	fActiveBreakpoint = breakpoint;
682 
683 	if (fActiveBreakpoint != NULL) {
684 		fActiveBreakpoint->AcquireReference();
685 
686 		// get the breakpoint's function (more exactly: some function instance)
687 		AutoLocker< ::Team> locker(fTeam);
688 
689 		Function* function = fTeam->FunctionByID(
690 			breakpoint->Location().GetFunctionID());
691 		FunctionInstance* functionInstance = function != NULL
692 			? function->FirstInstance() : NULL;
693 		BReference<FunctionInstance> functionInstanceReference(
694 			functionInstance);
695 
696 		locker.Unlock();
697 
698 		fActiveSourceObject = ACTIVE_SOURCE_BREAKPOINT;
699 
700 		_SetActiveFunction(functionInstance);
701 
702 		// scroll to the breakpoint's source code line number (it is not done
703 		// automatically, if the active function remains the same)
704 		_ScrollToActiveFunction();
705 	}
706 
707 	fBreakpointsView->SetBreakpoint(fActiveBreakpoint);
708 }
709 
710 
711 void
712 TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance)
713 {
714 // TODO: If a function is selected by other means than via selecting a stack
715 // frame, we should still select a matching stack frame, if it features the
716 // same function.
717 	if (functionInstance == fActiveFunction)
718 		return;
719 
720 	AutoLocker< ::Team> locker(fTeam);
721 
722 	if (fActiveFunction != NULL) {
723 		fActiveFunction->GetFunction()->RemoveListener(this);
724 		fActiveFunction->ReleaseReference();
725 	}
726 
727 	// to avoid listener feedback problems, first unset the active function and
728 	// set the new image, if any
729 	locker.Unlock();
730 
731 	fActiveFunction = NULL;
732 
733 	if (functionInstance != NULL)
734 		_SetActiveImage(fTeam->ImageByAddress(functionInstance->Address()));
735 
736 	fActiveFunction = functionInstance;
737 
738 	locker.Lock();
739 
740 	SourceCode* sourceCode = NULL;
741 	BReference<SourceCode> sourceCodeReference;
742 
743 	if (fActiveFunction != NULL) {
744 		fActiveFunction->AcquireReference();
745 		fActiveFunction->GetFunction()->AddListener(this);
746 
747 		Function* function = fActiveFunction->GetFunction();
748 		sourceCode = function->GetSourceCode();
749 		if (sourceCode == NULL)
750 			sourceCode = fActiveFunction->GetSourceCode();
751 		sourceCodeReference.SetTo(sourceCode);
752 
753 		// If the source code is not loaded yet, request it.
754 		if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED)
755 			fListener->FunctionSourceCodeRequested(fActiveFunction);
756 	}
757 
758 	locker.Unlock();
759 
760 	_SetActiveSourceCode(sourceCode);
761 
762 	fImageFunctionsView->SetFunction(fActiveFunction);
763 }
764 
765 
766 void
767 TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
768 {
769 	if (sourceCode == fActiveSourceCode) {
770 		_ScrollToActiveFunction();
771 		return;
772 	}
773 
774 	if (fActiveSourceCode != NULL)
775 		fActiveSourceCode->ReleaseReference();
776 
777 	fActiveSourceCode = sourceCode;
778 
779 	if (fActiveSourceCode != NULL)
780 		fActiveSourceCode->AcquireReference();
781 
782 	fSourceView->SetSourceCode(fActiveSourceCode);
783 
784 	_ScrollToActiveFunction();
785 }
786 
787 void
788 TeamWindow::_UpdateCpuState()
789 {
790 	// get the CPU state
791 	CpuState* cpuState = NULL;
792 	BReference<CpuState> cpuStateReference;
793 		// hold a reference until the register view has one
794 
795 	if (fActiveThread != NULL) {
796 		// Get the CPU state from the active stack frame or the thread directly.
797 		if (fActiveStackFrame == NULL) {
798 			AutoLocker< ::Team> locker(fTeam);
799 			cpuState = fActiveThread->GetCpuState();
800 			cpuStateReference.SetTo(cpuState);
801 			locker.Unlock();
802 		} else
803 			cpuState = fActiveStackFrame->GetCpuState();
804 	}
805 
806 	fRegistersView->SetCpuState(cpuState);
807 }
808 
809 
810 void
811 TeamWindow::_UpdateRunButtons()
812 {
813 	uint32 threadState = fActiveThread != NULL
814 		? fActiveThread->State() : THREAD_STATE_UNKNOWN;
815 
816 	switch (threadState) {
817 		case THREAD_STATE_UNKNOWN:
818 			fRunButton->SetEnabled(false);
819 			fStepOverButton->SetEnabled(false);
820 			fStepIntoButton->SetEnabled(false);
821 			fStepOutButton->SetEnabled(false);
822 			break;
823 		case THREAD_STATE_RUNNING:
824 			fRunButton->SetLabel("Debug");
825 			fRunButton->SetMessage(new BMessage(MSG_THREAD_STOP));
826 			fRunButton->SetEnabled(true);
827 			fStepOverButton->SetEnabled(false);
828 			fStepIntoButton->SetEnabled(false);
829 			fStepOutButton->SetEnabled(false);
830 			break;
831 		case THREAD_STATE_STOPPED:
832 			fRunButton->SetLabel("Run");
833 			fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
834 			fRunButton->SetEnabled(true);
835 			fStepOverButton->SetEnabled(true);
836 			fStepIntoButton->SetEnabled(true);
837 			fStepOutButton->SetEnabled(true);
838 			break;
839 	}
840 }
841 
842 
843 void
844 TeamWindow::_ScrollToActiveFunction()
845 {
846 	// Scroll to the active function, if it has been selected manually.
847 	if (fActiveFunction == NULL || fActiveSourceCode == NULL)
848 		return;
849 
850 	switch (fActiveSourceObject) {
851 		case ACTIVE_SOURCE_FUNCTION:
852 			fSourceView->ScrollToAddress(fActiveFunction->Address());
853 			break;
854 		case ACTIVE_SOURCE_BREAKPOINT:
855 		{
856 			if (fActiveBreakpoint == NULL)
857 				break;
858 
859 			const UserBreakpointLocation& location
860 				= fActiveBreakpoint->Location();
861 			int32 line = location.GetSourceLocation().Line();
862 
863 			if (location.SourceFile() != NULL && line >= 0
864 				&& fActiveSourceCode->GetSourceFile()
865 					== location.SourceFile()) {
866 				fSourceView->ScrollToLine(line);
867 			} else {
868 				fSourceView->ScrollToAddress(
869 					fActiveFunction->Address()
870 						+ location.RelativeAddress());
871 			}
872 			break;
873 		}
874 		case ACTIVE_SOURCE_NONE:
875 		case ACTIVE_SOURCE_STACK_FRAME:
876 			break;
877 	}
878 }
879 
880 
881 void
882 TeamWindow::_HandleThreadStateChanged(thread_id threadID)
883 {
884 	AutoLocker< ::Team> locker(fTeam);
885 
886 	::Thread* thread = fTeam->ThreadByID(threadID);
887 	if (thread == NULL)
888 		return;
889 
890 	// If the thread has been stopped and we don't have an active thread yet
891 	// (or it isn't stopped), switch to this thread. Otherwise ignore the event.
892 	if (thread->State() == THREAD_STATE_STOPPED
893 		&& (fActiveThread == NULL
894 			|| (thread != fActiveThread
895 				&& fActiveThread->State() != THREAD_STATE_STOPPED))) {
896 		_SetActiveThread(thread);
897 	} else if (thread != fActiveThread) {
898 		// otherwise ignore the event, if the thread is not the active one
899 		return;
900 	}
901 
902 	// Switch to the threads tab view when the thread has stopped.
903 	if (thread->State() == THREAD_STATE_STOPPED)
904 		fTabView->Select(MAIN_TAB_INDEX_THREADS);
905 
906 	_UpdateRunButtons();
907 }
908 
909 
910 void
911 TeamWindow::_HandleCpuStateChanged(thread_id threadID)
912 {
913 	// We're only interested in the currently selected thread
914 	if (fActiveThread == NULL || threadID != fActiveThread->ID())
915 		return;
916 
917 	_UpdateCpuState();
918 }
919 
920 
921 void
922 TeamWindow::_HandleStackTraceChanged(thread_id threadID)
923 {
924 	// We're only interested in the currently selected thread
925 	if (fActiveThread == NULL || threadID != fActiveThread->ID())
926 		return;
927 
928 	AutoLocker< ::Team> locker(fTeam);
929 
930 	StackTrace* stackTrace = fActiveThread != NULL
931 		? fActiveThread->GetStackTrace() : NULL;
932 	BReference<StackTrace> stackTraceReference(stackTrace);
933 		// hold a reference until the register view has one
934 
935 	locker.Unlock();
936 
937 	_SetActiveStackTrace(stackTrace);
938 }
939 
940 
941 void
942 TeamWindow::_HandleImageDebugInfoChanged(image_id imageID)
943 {
944 	TRACE_GUI("TeamWindow::_HandleImageDebugInfoChanged(%ld)\n", imageID);
945 
946 	// We're only interested in the currently selected thread
947 	if (fActiveImage == NULL || imageID != fActiveImage->ID())
948 		return;
949 
950 	AutoLocker< ::Team> locker(fTeam);
951 
952 	ImageDebugInfo* imageDebugInfo = fActiveImage != NULL
953 		? fActiveImage->GetImageDebugInfo() : NULL;
954 
955 	TRACE_GUI("  image debug info: %p\n", imageDebugInfo);
956 
957 	BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo);
958 		// hold a reference until we've set it
959 
960 	locker.Unlock();
961 
962 	fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
963 }
964 
965 
966 void
967 TeamWindow::_HandleSourceCodeChanged()
968 {
969 	// If we don't have an active function anymore, the message is obsolete.
970 	if (fActiveFunction == NULL)
971 		return;
972 
973 	// get a reference to the source code
974 	AutoLocker< ::Team> locker(fTeam);
975 
976 	SourceCode* sourceCode = fActiveFunction->GetFunction()->GetSourceCode();
977 	if (sourceCode == NULL) {
978 		sourceCode = fActiveFunction->GetSourceCode();
979 
980 		BString sourceText;
981 		LocatableFile* sourceFile = fActiveFunction->GetFunctionDebugInfo()
982 			->SourceFile();
983 		if (sourceFile != NULL && !sourceFile->GetLocatedPath(sourceText))
984 			sourceFile->GetPath(sourceText);
985 
986 		if (sourceCode != NULL && sourceCode->GetSourceFile() == NULL
987 			&& sourceFile != NULL) {
988 			sourceText.Prepend("Click to locate source file '");
989 			sourceText += "'";
990 			fSourcePathView->SetText(sourceText.String());
991 		} else if (sourceFile != NULL) {
992 			sourceText.Prepend("File: ");
993 			fSourcePathView->SetText(sourceText.String());
994 		} else
995 			fSourcePathView->SetText("Source file unavailable.");
996 	}
997 
998 	BReference<SourceCode> sourceCodeReference(sourceCode);
999 
1000 	locker.Unlock();
1001 
1002 	_SetActiveSourceCode(sourceCode);
1003 }
1004 
1005 
1006 void
1007 TeamWindow::_HandleUserBreakpointChanged(UserBreakpoint* breakpoint)
1008 {
1009 	fSourceView->UserBreakpointChanged(breakpoint);
1010 	fBreakpointsView->UserBreakpointChanged(breakpoint);
1011 }
1012 
1013 
1014 void
1015 TeamWindow::_HandleResolveMissingSourceFile(entry_ref& locatedPath)
1016 {
1017 	if (fActiveFunction != NULL) {
1018 		LocatableFile* sourceFile = fActiveFunction->GetFunctionDebugInfo()
1019 			->SourceFile();
1020 		if (sourceFile != NULL) {
1021 			BString sourcePath;
1022 			BString targetPath;
1023 			sourceFile->GetPath(sourcePath);
1024 			BPath path(&locatedPath);
1025 			targetPath = path.Path();
1026 			fListener->SourceEntryLocateRequested(sourcePath, targetPath);
1027 			fListener->FunctionSourceCodeRequested(fActiveFunction);
1028 		}
1029 	}
1030 }
1031