xref: /haiku/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp (revision a629567a9001547736cfe892cdf992be16868fed)
1 /*
2  * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2010-2014, 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 <Alert.h>
13 #include <Button.h>
14 #include <FilePanel.h>
15 #include <FindDirectory.h>
16 #include <LayoutBuilder.h>
17 #include <Menu.h>
18 #include <MenuBar.h>
19 #include <MenuItem.h>
20 #include <Message.h>
21 #include <MessageFilter.h>
22 #include <MessageRunner.h>
23 #include <Path.h>
24 #include <PopUpMenu.h>
25 #include <Query.h>
26 #include <StringView.h>
27 #include <TabView.h>
28 #include <ScrollView.h>
29 #include <SplitView.h>
30 #include <TextView.h>
31 #include <VolumeRoster.h>
32 
33 #include <AutoDeleter.h>
34 #include <AutoLocker.h>
35 
36 #include "Breakpoint.h"
37 #include "ConsoleOutputView.h"
38 #include "CpuState.h"
39 #include "DisassembledCode.h"
40 #include "BreakConditionConfigWindow.h"
41 #include "FileSourceCode.h"
42 #include "GuiSettingsUtils.h"
43 #include "GuiTeamUiSettings.h"
44 #include "Image.h"
45 #include "ImageDebugInfo.h"
46 #include "InspectorWindow.h"
47 #include "LocatableFile.h"
48 #include "MessageCodes.h"
49 #include "RegistersView.h"
50 #include "StackTrace.h"
51 #include "StackTraceView.h"
52 #include "Tracing.h"
53 #include "TypeComponentPath.h"
54 #include "UiUtils.h"
55 #include "UserInterface.h"
56 #include "Variable.h"
57 #include "WatchPromptWindow.h"
58 
59 
60 enum {
61 	MAIN_TAB_INDEX_THREADS	= 0,
62 	MAIN_TAB_INDEX_IMAGES	= 1
63 };
64 
65 
66 enum {
67 	MSG_CHOOSE_DEBUG_REPORT_LOCATION	= 'ccrl',
68 	MSG_DEBUG_REPORT_SAVED				= 'drsa',
69 	MSG_LOCATE_SOURCE_IF_NEEDED			= 'lsin',
70 	MSG_SOURCE_ENTRY_QUERY_COMPLETE		= 'seqc',
71 	MSG_CLEAR_STACK_TRACE				= 'clst'
72 };
73 
74 
75 class PathViewMessageFilter : public BMessageFilter {
76 public:
77 		PathViewMessageFilter(BMessenger teamWindow)
78 			:
79 			BMessageFilter(B_MOUSE_UP),
80 			fTeamWindowMessenger(teamWindow)
81 		{
82 		}
83 
84 		virtual filter_result Filter(BMessage*, BHandler**)
85 		{
86 			fTeamWindowMessenger.SendMessage(MSG_LOCATE_SOURCE_IF_NEEDED);
87 
88 			return B_DISPATCH_MESSAGE;
89 		}
90 
91 private:
92 		BMessenger fTeamWindowMessenger;
93 };
94 
95 
96 // #pragma mark - TeamWindow
97 
98 
99 TeamWindow::TeamWindow(::Team* team, UserInterfaceListener* listener)
100 	:
101 	BWindow(BRect(100, 100, 899, 699), "Team", B_TITLED_WINDOW,
102 		B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
103 	fTeam(team),
104 	fActiveThread(NULL),
105 	fActiveImage(NULL),
106 	fActiveStackTrace(NULL),
107 	fActiveStackFrame(NULL),
108 	fActiveBreakpoint(NULL),
109 	fActiveFunction(NULL),
110 	fActiveSourceCode(NULL),
111 	fActiveSourceObject(ACTIVE_SOURCE_NONE),
112 	fListener(listener),
113 	fTraceUpdateRunner(NULL),
114 	fTabView(NULL),
115 	fLocalsTabView(NULL),
116 	fThreadListView(NULL),
117 	fImageListView(NULL),
118 	fImageFunctionsView(NULL),
119 	fBreakpointsView(NULL),
120 	fVariablesView(NULL),
121 	fRegistersView(NULL),
122 	fStackTraceView(NULL),
123 	fSourceView(NULL),
124 	fRunButton(NULL),
125 	fStepOverButton(NULL),
126 	fStepIntoButton(NULL),
127 	fStepOutButton(NULL),
128 	fMenuBar(NULL),
129 	fSourcePathView(NULL),
130 	fConsoleOutputView(NULL),
131 	fFunctionSplitView(NULL),
132 	fSourceSplitView(NULL),
133 	fImageSplitView(NULL),
134 	fThreadSplitView(NULL),
135 	fConsoleSplitView(NULL),
136 	fBreakConditionConfigWindow(NULL),
137 	fInspectorWindow(NULL),
138 	fFilePanel(NULL),
139 	fActiveSourceWorker(-1)
140 {
141 	fTeam->Lock();
142 	BString name = fTeam->Name();
143 	fTeam->Unlock();
144 	if (fTeam->ID() >= 0)
145 		name << " (" << fTeam->ID() << ")";
146 	SetTitle(name.String());
147 
148 	fTeam->AddListener(this);
149 }
150 
151 
152 TeamWindow::~TeamWindow()
153 {
154 	if (fThreadListView != NULL)
155 		fThreadListView->UnsetListener();
156 	if (fStackTraceView != NULL)
157 		fStackTraceView->UnsetListener();
158 	if (fSourceView != NULL)
159 		fSourceView->UnsetListener();
160 	if (fInspectorWindow != NULL) {
161 		BMessenger messenger(fInspectorWindow);
162 		if (messenger.LockTarget())
163 			fInspectorWindow->Quit();
164 	}
165 
166 	fTeam->RemoveListener(this);
167 
168 	_SetActiveSourceCode(NULL);
169 	_SetActiveFunction(NULL);
170 	_SetActiveBreakpoint(NULL);
171 	_SetActiveStackFrame(NULL);
172 	_SetActiveStackTrace(NULL);
173 	_SetActiveImage(NULL);
174 	_SetActiveThread(NULL);
175 
176 	delete fFilePanel;
177 
178 	if (fActiveSourceWorker > 0)
179 		wait_for_thread(fActiveSourceWorker, NULL);
180 }
181 
182 
183 /*static*/ TeamWindow*
184 TeamWindow::Create(::Team* team, UserInterfaceListener* listener)
185 {
186 	TeamWindow* self = new TeamWindow(team, listener);
187 
188 	try {
189 		self->_Init();
190 	} catch (...) {
191 		delete self;
192 		throw;
193 	}
194 
195 	return self;
196 }
197 
198 
199 void
200 TeamWindow::DispatchMessage(BMessage* message, BHandler* handler)
201 {
202 	// Handle function key shortcuts for stepping
203 	switch (message->what) {
204 		case B_KEY_DOWN:
205 			if (fActiveThread != NULL && fTraceUpdateRunner == NULL) {
206 				int32 key;
207 				uint32 modifiers;
208 				if (message->FindInt32("key", &key) == B_OK
209 					&& message->FindInt32("modifiers", (int32*)&modifiers)
210 					== B_OK) {
211 					switch (key) {
212 						case B_F5_KEY:
213 							fListener->ThreadActionRequested(
214 								fActiveThread->ID(), MSG_THREAD_RUN);
215 							break;
216 						case B_F10_KEY:
217 							fListener->ThreadActionRequested(
218 								fActiveThread->ID(), MSG_THREAD_STEP_OVER);
219 							break;
220 						case B_F11_KEY:
221 							if ((modifiers & B_SHIFT_KEY) != 0) {
222 								fListener->ThreadActionRequested(
223 									fActiveThread->ID(), MSG_THREAD_STEP_OUT);
224 							} else {
225 								fListener->ThreadActionRequested(
226 									fActiveThread->ID(), MSG_THREAD_STEP_INTO);
227 							}
228 							break;
229 						default:
230 							break;
231 					}
232 				}
233 			}
234 			break;
235 
236 		case B_COPY:
237 		case B_SELECT_ALL:
238 			BView* focusView = CurrentFocus();
239 			if (focusView != NULL) {
240 				focusView->MessageReceived(message);
241 				return;
242 			}
243 			break;
244 	}
245 	BWindow::DispatchMessage(message, handler);
246 }
247 
248 
249 void
250 TeamWindow::MessageReceived(BMessage* message)
251 {
252 	switch (message->what) {
253 		case MSG_TEAM_RESTART_REQUESTED:
254 		{
255 			fListener->TeamRestartRequested();
256 			break;
257 		}
258 		case MSG_CHOOSE_DEBUG_REPORT_LOCATION:
259 		{
260 			try {
261 				char filename[B_FILE_NAME_LENGTH];
262 				UiUtils::ReportNameForTeam(fTeam, filename, sizeof(filename));
263 				BMessenger msgr(this);
264 				fFilePanel = new BFilePanel(B_SAVE_PANEL, &msgr,
265 					NULL, 0, false, new BMessage(MSG_GENERATE_DEBUG_REPORT));
266 				fFilePanel->SetSaveText(filename);
267 				fFilePanel->Show();
268 			} catch (...) {
269 				delete fFilePanel;
270 				fFilePanel = NULL;
271 			}
272 			break;
273 		}
274 		case MSG_GENERATE_DEBUG_REPORT:
275 		{
276 			delete fFilePanel;
277 			fFilePanel = NULL;
278 
279 			BPath path;
280 			entry_ref ref;
281 			if (message->FindRef("directory", &ref) == B_OK
282 				&& message->HasString("name")) {
283 				path.SetTo(&ref);
284 				path.Append(message->FindString("name"));
285 				if (get_ref_for_path(path.Path(), &ref) == B_OK)
286 					fListener->DebugReportRequested(&ref);
287 			}
288 			break;
289 		}
290 		case MSG_DEBUG_REPORT_SAVED:
291 		{
292 			BString data;
293 			data.SetToFormat("Debug report successfully saved to '%s'",
294 				message->FindString("path"));
295 			BAlert *alert = new(std::nothrow) BAlert("Report saved",
296 				data.String(), "Close");
297 			if (alert == NULL)
298 				break;
299 
300 			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
301 			alert->Go();
302 			break;
303 		}
304 		case MSG_SHOW_INSPECTOR_WINDOW:
305 		{
306 			if (fInspectorWindow) {
307 				fInspectorWindow->Activate(true);
308 			} else {
309 				try {
310 					fInspectorWindow = InspectorWindow::Create(fTeam,
311 						fListener, this);
312 					if (fInspectorWindow != NULL) {
313 						BMessage settings;
314 						fInspectorWindow->LoadSettings(fUiSettings);
315 						fInspectorWindow->Show();
316 					}
317 	           	} catch (...) {
318 	           		// TODO: notify user
319 	           	}
320 			}
321 
322 			target_addr_t address;
323 			if (message->FindUInt64("address", &address) == B_OK) {
324 				BMessage addressMessage(MSG_INSPECT_ADDRESS);
325 				addressMessage.AddUInt64("address", address);
326 				fInspectorWindow->PostMessage(&addressMessage);
327 			}
328            	break;
329 		}
330 		case MSG_INSPECTOR_WINDOW_CLOSED:
331 		{
332 			_SaveInspectorSettings(CurrentMessage());
333 			fInspectorWindow = NULL;
334 			break;
335 
336 		}
337 		case MSG_SHOW_BREAK_CONDITION_CONFIG_WINDOW:
338 		{
339 			if (fBreakConditionConfigWindow) {
340 				fBreakConditionConfigWindow->Activate(true);
341 			} else {
342 				try {
343 					fBreakConditionConfigWindow
344 						= BreakConditionConfigWindow::Create(
345 						fTeam, fListener, this);
346 					if (fBreakConditionConfigWindow != NULL)
347 						fBreakConditionConfigWindow->Show();
348 	           	} catch (...) {
349 	           		// TODO: notify user
350 	           	}
351 			}
352 			break;
353 		}
354 		case MSG_BREAK_CONDITION_CONFIG_WINDOW_CLOSED:
355 		{
356 			fBreakConditionConfigWindow = NULL;
357 			break;
358 		}
359 		case MSG_SHOW_WATCH_VARIABLE_PROMPT:
360 		{
361 			target_addr_t address;
362 			uint32 type;
363 			int32 length;
364 
365 			if (message->FindUInt64("address", &address) != B_OK
366 				|| message->FindUInt32("type", &type) != B_OK
367 				|| message->FindInt32("length", &length) != B_OK) {
368 				break;
369 			}
370 
371 			try {
372 				WatchPromptWindow* window = WatchPromptWindow::Create(
373 					fTeam->GetArchitecture(), address, type, length,
374 					fListener);
375 				window->Show();
376 			} catch (...) {
377 				// TODO: notify user
378 			}
379 			break;
380 		}
381 		case B_REFS_RECEIVED:
382 		{
383 			entry_ref locatedPath;
384 			if (message->FindRef("refs", &locatedPath) != B_OK)
385 				break;
386 
387 			_HandleResolveMissingSourceFile(locatedPath);
388 			break;
389 		}
390 		case MSG_LOCATE_SOURCE_IF_NEEDED:
391 		{
392 			_HandleLocateSourceRequest();
393 			break;
394 		}
395 		case MSG_SOURCE_ENTRY_QUERY_COMPLETE:
396 		{
397 			BStringList* entries;
398 			if (message->FindPointer("entries", (void**)&entries) != B_OK)
399 				break;
400 			ObjectDeleter<BStringList> entryDeleter(entries);
401 			_HandleLocateSourceRequest(entries);
402 			fActiveSourceWorker = -1;
403 			break;
404 		}
405 		case MSG_THREAD_RUN:
406 		case MSG_THREAD_STOP:
407 		case MSG_THREAD_STEP_OVER:
408 		case MSG_THREAD_STEP_INTO:
409 		case MSG_THREAD_STEP_OUT:
410 			if (fActiveThread != NULL && fTraceUpdateRunner == NULL) {
411 				fListener->ThreadActionRequested(fActiveThread->ID(),
412 					message->what);
413 			}
414 			break;
415 
416 		case MSG_CLEAR_STACK_TRACE:
417 		{
418 			if (fTraceUpdateRunner != NULL) {
419 				_SetActiveStackTrace(NULL);
420 				_UpdateRunButtons();
421 			}
422 			break;
423 		}
424 		case MSG_THREAD_STATE_CHANGED:
425 		{
426 			int32 threadID;
427 			if (message->FindInt32("thread", &threadID) != B_OK)
428 				break;
429 
430 			_HandleThreadStateChanged(threadID);
431 			break;
432 		}
433 		case MSG_THREAD_CPU_STATE_CHANGED:
434 		{
435 			int32 threadID;
436 			if (message->FindInt32("thread", &threadID) != B_OK)
437 				break;
438 
439 			_HandleCpuStateChanged(threadID);
440 			break;
441 		}
442 
443 		case MSG_THREAD_STACK_TRACE_CHANGED:
444 		{
445 			int32 threadID;
446 			if (message->FindInt32("thread", &threadID) != B_OK)
447 				break;
448 
449 			_HandleStackTraceChanged(threadID);
450 			break;
451 		}
452 
453 		case MSG_IMAGE_DEBUG_INFO_CHANGED:
454 		{
455 			int32 imageID;
456 			if (message->FindInt32("image", &imageID) != B_OK)
457 				break;
458 
459 			_HandleImageDebugInfoChanged(imageID);
460 			break;
461 		}
462 
463 		case MSG_CONSOLE_OUTPUT_RECEIVED:
464 		{
465 			int32 fd;
466 			BString output;
467 			if (message->FindInt32("fd", &fd) != B_OK
468 					|| message->FindString("output", &output) != B_OK) {
469 				break;
470 			}
471 			fConsoleOutputView->ConsoleOutputReceived(fd, output);
472 			break;
473 		}
474 
475 		case MSG_USER_BREAKPOINT_CHANGED:
476 		{
477 			UserBreakpoint* breakpoint;
478 			if (message->FindPointer("breakpoint", (void**)&breakpoint) != B_OK)
479 				break;
480 			BReference<UserBreakpoint> breakpointReference(breakpoint, true);
481 
482 			_HandleUserBreakpointChanged(breakpoint);
483 			break;
484 		}
485 
486 		case MSG_WATCHPOINT_CHANGED:
487 		{
488 			Watchpoint* watchpoint;
489 			if (message->FindPointer("watchpoint", (void**)&watchpoint) != B_OK)
490 				break;
491 			BReference<Watchpoint> watchpointReference(watchpoint, true);
492 
493 			_HandleWatchpointChanged(watchpoint);
494 			break;
495 
496 		}
497 
498 		case MSG_FUNCTION_SOURCE_CODE_CHANGED:
499 		{
500 			_HandleSourceCodeChanged();
501 			break;
502 		}
503 
504 		default:
505 			BWindow::MessageReceived(message);
506 			break;
507 	}
508 }
509 
510 
511 bool
512 TeamWindow::QuitRequested()
513 {
514 	fListener->UserInterfaceQuitRequested();
515 
516 	return false;
517 }
518 
519 
520 status_t
521 TeamWindow::LoadSettings(const GuiTeamUiSettings* settings)
522 {
523 	AutoLocker<BWindow> lock(this);
524 	if (!lock.IsLocked())
525 		return B_ERROR;
526 
527 	BMessage teamWindowSettings;
528 	// no settings stored yet
529 	if (settings->Settings("teamWindow", teamWindowSettings) != B_OK)
530 		return B_OK;
531 
532 	BRect frame;
533 	if (teamWindowSettings.FindRect("frame", &frame) == B_OK) {
534 		ResizeTo(frame.Width(), frame.Height());
535 		MoveTo(frame.left, frame.top);
536 	}
537 
538 	BMessage archive;
539 	if (teamWindowSettings.FindMessage("sourceSplit", &archive) == B_OK)
540 		GuiSettingsUtils::UnarchiveSplitView(archive, fSourceSplitView);
541 
542 	if (teamWindowSettings.FindMessage("functionSplit", &archive) == B_OK)
543 		GuiSettingsUtils::UnarchiveSplitView(archive, fFunctionSplitView);
544 
545 	if (teamWindowSettings.FindMessage("imageSplit", &archive) == B_OK)
546 		GuiSettingsUtils::UnarchiveSplitView(archive, fImageSplitView);
547 
548 	if (teamWindowSettings.FindMessage("threadSplit", &archive) == B_OK)
549 		GuiSettingsUtils::UnarchiveSplitView(archive, fThreadSplitView);
550 
551 	if (teamWindowSettings.FindMessage("consoleSplit", &archive) == B_OK)
552 		GuiSettingsUtils::UnarchiveSplitView(archive, fConsoleSplitView);
553 
554 	if (teamWindowSettings.FindMessage("imageListView", &archive) == B_OK)
555 		fImageListView->LoadSettings(archive);
556 
557 	if (teamWindowSettings.FindMessage("imageFunctionsView", &archive) == B_OK)
558 		fImageFunctionsView->LoadSettings(archive);
559 
560 	if (teamWindowSettings.FindMessage("threadListView", &archive) == B_OK)
561 		fThreadListView->LoadSettings(archive);
562 
563 	if (teamWindowSettings.FindMessage("variablesView", &archive) == B_OK)
564 		fVariablesView->LoadSettings(archive);
565 
566 	if (teamWindowSettings.FindMessage("registersView", &archive) == B_OK)
567 		fRegistersView->LoadSettings(archive);
568 
569 	if (teamWindowSettings.FindMessage("stackTraceView", &archive) == B_OK)
570 		fStackTraceView->LoadSettings(archive);
571 
572 	if (teamWindowSettings.FindMessage("breakpointsView", &archive) == B_OK)
573 		fBreakpointsView->LoadSettings(archive);
574 
575 	if (teamWindowSettings.FindMessage("consoleOutputView", &archive) == B_OK)
576 		fConsoleOutputView->LoadSettings(archive);
577 
578 	fUiSettings = *settings;
579 
580 	return B_OK;
581 }
582 
583 
584 status_t
585 TeamWindow::SaveSettings(GuiTeamUiSettings* settings)
586 {
587 	AutoLocker<BWindow> lock(this);
588 	if (!lock.IsLocked())
589 		return B_ERROR;
590 
591 	BMessage inspectorSettings;
592 	if (fUiSettings.Settings("inspectorWindow", inspectorSettings) == B_OK) {
593 		if (!settings->AddSettings("inspectorWindow", inspectorSettings))
594 			return B_NO_MEMORY;
595 	}
596 
597 	BMessage archive;
598 	BMessage teamWindowSettings;
599 	if (teamWindowSettings.AddRect("frame", Frame()) != B_OK)
600 		return B_NO_MEMORY;
601 
602 	if (GuiSettingsUtils::ArchiveSplitView(archive, fSourceSplitView) != B_OK)
603 		return B_NO_MEMORY;
604 	if (teamWindowSettings.AddMessage("sourceSplit", &archive) != B_OK)
605 		return B_NO_MEMORY;
606 
607 	if (GuiSettingsUtils::ArchiveSplitView(archive, fFunctionSplitView) != B_OK)
608 		return B_NO_MEMORY;
609 	if (teamWindowSettings.AddMessage("functionSplit", &archive) != B_OK)
610 		return B_NO_MEMORY;
611 
612 	if (GuiSettingsUtils::ArchiveSplitView(archive, fImageSplitView) != B_OK)
613 		return B_NO_MEMORY;
614 	if (teamWindowSettings.AddMessage("imageSplit", &archive))
615 		return B_NO_MEMORY;
616 
617 	if (GuiSettingsUtils::ArchiveSplitView(archive, fThreadSplitView) != B_OK)
618 		return B_NO_MEMORY;
619 	if (teamWindowSettings.AddMessage("threadSplit", &archive))
620 		return B_NO_MEMORY;
621 
622 	if (GuiSettingsUtils::ArchiveSplitView(archive, fConsoleSplitView) != B_OK)
623 		return B_NO_MEMORY;
624 	if (teamWindowSettings.AddMessage("consoleSplit", &archive))
625 		return B_NO_MEMORY;
626 
627 	if (fImageListView->SaveSettings(archive) != B_OK)
628 		return B_NO_MEMORY;
629 	if (teamWindowSettings.AddMessage("imageListView", &archive))
630 		return B_NO_MEMORY;
631 
632 	if (fImageFunctionsView->SaveSettings(archive) != B_OK)
633 		return B_NO_MEMORY;
634 	if (teamWindowSettings.AddMessage("imageFunctionsView", &archive))
635 		return B_NO_MEMORY;
636 
637 	if (fThreadListView->SaveSettings(archive) != B_OK)
638 		return B_NO_MEMORY;
639 	if (teamWindowSettings.AddMessage("threadListView", &archive))
640 		return B_NO_MEMORY;
641 
642 	if (fVariablesView->SaveSettings(archive) != B_OK)
643 		return B_NO_MEMORY;
644 	if (teamWindowSettings.AddMessage("variablesView", &archive))
645 		return B_NO_MEMORY;
646 
647 	if (fRegistersView->SaveSettings(archive) != B_OK)
648 		return B_NO_MEMORY;
649 	if (teamWindowSettings.AddMessage("registersView", &archive))
650 		return B_NO_MEMORY;
651 
652 	if (fStackTraceView->SaveSettings(archive) != B_OK)
653 		return B_NO_MEMORY;
654 	if (teamWindowSettings.AddMessage("stackTraceView", &archive))
655 		return B_NO_MEMORY;
656 
657 	if (fBreakpointsView->SaveSettings(archive) != B_OK)
658 		return B_NO_MEMORY;
659 	if (teamWindowSettings.AddMessage("breakpointsView", &archive))
660 		return B_NO_MEMORY;
661 
662 	if (fConsoleOutputView->SaveSettings(archive) != B_OK)
663 		return B_NO_MEMORY;
664 	if (teamWindowSettings.AddMessage("consoleOutputView", &archive))
665 		return B_NO_MEMORY;
666 
667 	if (!settings->AddSettings("teamWindow", teamWindowSettings))
668 		return B_NO_MEMORY;
669 
670 	return B_OK;
671 }
672 
673 
674 void
675 TeamWindow::ThreadSelectionChanged(::Thread* thread)
676 {
677 	_SetActiveThread(thread);
678 }
679 
680 
681 void
682 TeamWindow::ImageSelectionChanged(Image* image)
683 {
684 	_SetActiveImage(image);
685 }
686 
687 
688 void
689 TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
690 {
691 	_SetActiveStackFrame(frame);
692 }
693 
694 
695 void
696 TeamWindow::FunctionSelectionChanged(FunctionInstance* function)
697 {
698 	// If the function wasn't already active, it was just selected by the user.
699 	if (function != NULL && function != fActiveFunction)
700 		fActiveSourceObject = ACTIVE_SOURCE_FUNCTION;
701 
702 	_SetActiveFunction(function);
703 }
704 
705 
706 void
707 TeamWindow::BreakpointSelectionChanged(BreakpointProxyList &proxies)
708 {
709 	if (proxies.CountItems() == 0 && fActiveBreakpoint != NULL) {
710 		fActiveBreakpoint->ReleaseReference();
711 		fActiveBreakpoint = NULL;
712 	} else if (proxies.CountItems() == 1) {
713 		BreakpointProxy* proxy = proxies.ItemAt(0);
714 		if (proxy->Type() == BREAKPOINT_PROXY_TYPE_BREAKPOINT)
715 			_SetActiveBreakpoint(proxy->GetBreakpoint());
716 	}
717 	// if more than one item is selected, do nothing.
718 }
719 
720 
721 void
722 TeamWindow::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
723 	bool enabled)
724 {
725 	fListener->SetBreakpointEnabledRequested(breakpoint, enabled);
726 }
727 
728 
729 void
730 TeamWindow::ClearBreakpointRequested(UserBreakpoint* breakpoint)
731 {
732 	fListener->ClearBreakpointRequested(breakpoint);
733 }
734 
735 
736 void
737 TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled)
738 {
739 	fListener->SetBreakpointRequested(address, enabled);
740 }
741 
742 
743 void
744 TeamWindow::ClearBreakpointRequested(target_addr_t address)
745 {
746 	fListener->ClearBreakpointRequested(address);
747 }
748 
749 
750 void
751 TeamWindow::ThreadActionRequested(::Thread* thread, uint32 action,
752 	target_addr_t address)
753 {
754 	if (fTraceUpdateRunner == NULL)
755 		fListener->ThreadActionRequested(thread->ID(), action, address);
756 }
757 
758 
759 void
760 TeamWindow::FunctionSourceCodeRequested(FunctionInstance* function,
761 	bool forceDisassembly)
762 {
763 	fListener->FunctionSourceCodeRequested(function, forceDisassembly);
764 }
765 
766 
767 void
768 TeamWindow::SetWatchpointEnabledRequested(Watchpoint* watchpoint,
769 	bool enabled)
770 {
771 	fListener->SetWatchpointEnabledRequested(watchpoint, enabled);
772 }
773 
774 
775 void
776 TeamWindow::ClearWatchpointRequested(Watchpoint* watchpoint)
777 {
778 	fListener->ClearWatchpointRequested(watchpoint);
779 }
780 
781 
782 void
783 TeamWindow::ValueNodeValueRequested(CpuState* cpuState,
784 	ValueNodeContainer* container, ValueNode* valueNode)
785 {
786 	fListener->ValueNodeValueRequested(cpuState, container, valueNode);
787 }
788 
789 
790 void
791 TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event)
792 {
793 	BMessage message(MSG_THREAD_STATE_CHANGED);
794 	message.AddInt32("thread", event.GetThread()->ID());
795 	PostMessage(&message);
796 }
797 
798 
799 void
800 TeamWindow::ThreadCpuStateChanged(const Team::ThreadEvent& event)
801 {
802 	BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
803 	message.AddInt32("thread", event.GetThread()->ID());
804 	PostMessage(&message);
805 }
806 
807 
808 void
809 TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event)
810 {
811 	BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
812 	message.AddInt32("thread", event.GetThread()->ID());
813 	PostMessage(&message);
814 }
815 
816 
817 void
818 TeamWindow::ImageDebugInfoChanged(const Team::ImageEvent& event)
819 {
820 	BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
821 	message.AddInt32("image", event.GetImage()->ID());
822 	PostMessage(&message);
823 }
824 
825 
826 void
827 TeamWindow::ConsoleOutputReceived(const Team::ConsoleOutputEvent& event)
828 {
829 	BMessage message(MSG_CONSOLE_OUTPUT_RECEIVED);
830 	message.AddInt32("fd", event.Descriptor());
831 	message.AddString("output", event.Output());
832 	PostMessage(&message);
833 }
834 
835 
836 void
837 TeamWindow::UserBreakpointChanged(const Team::UserBreakpointEvent& event)
838 {
839 	BMessage message(MSG_USER_BREAKPOINT_CHANGED);
840 	BReference<UserBreakpoint> breakpointReference(event.GetBreakpoint());
841 	if (message.AddPointer("breakpoint", event.GetBreakpoint()) == B_OK
842 		&& PostMessage(&message) == B_OK) {
843 		breakpointReference.Detach();
844 	}
845 }
846 
847 
848 void
849 TeamWindow::WatchpointChanged(const Team::WatchpointEvent& event)
850 {
851 	BMessage message(MSG_WATCHPOINT_CHANGED);
852 	BReference<Watchpoint> watchpointReference(event.GetWatchpoint());
853 	if (message.AddPointer("watchpoint", event.GetWatchpoint()) == B_OK
854 		&& PostMessage(&message) == B_OK) {
855 		watchpointReference.Detach();
856 	}
857 }
858 
859 
860 void
861 TeamWindow::DebugReportChanged(const Team::DebugReportEvent& event)
862 {
863 	BMessage message(MSG_DEBUG_REPORT_SAVED);
864 	message.AddString("path", event.GetReportPath());
865 	PostMessage(&message);
866 }
867 
868 
869 void
870 TeamWindow::FunctionSourceCodeChanged(Function* function)
871 {
872 	TRACE_GUI("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, "
873 		"state: %d\n", function, function->GetSourceCode(),
874 		function->SourceCodeState());
875 
876 	PostMessage(MSG_FUNCTION_SOURCE_CODE_CHANGED);
877 }
878 
879 
880 void
881 TeamWindow::_Init()
882 {
883 	BScrollView* sourceScrollView;
884 
885 	const float splitSpacing = 3.0f;
886 
887 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0.0f)
888 		.Add(fMenuBar = new BMenuBar("Menu"))
889 		.AddSplit(B_VERTICAL, splitSpacing)
890 			.GetSplitView(&fFunctionSplitView)
891 			.SetInsets(B_USE_SMALL_INSETS)
892 			.Add(fTabView = new BTabView("tab view"), 0.4f)
893 			.AddSplit(B_HORIZONTAL, splitSpacing)
894 				.GetSplitView(&fSourceSplitView)
895 				.AddGroup(B_VERTICAL, B_USE_SMALL_SPACING)
896 					.AddGroup(B_HORIZONTAL, B_USE_SMALL_SPACING)
897 						.Add(fRunButton = new BButton("Run"))
898 						.Add(fStepOverButton = new BButton("Step over"))
899 						.Add(fStepIntoButton = new BButton("Step into"))
900 						.Add(fStepOutButton = new BButton("Step out"))
901 						.AddGlue()
902 					.End()
903 					.Add(fSourcePathView = new BStringView(
904 						"source path",
905 						"Source path unavailable."), 4.0f)
906 					.Add(sourceScrollView = new BScrollView("source scroll",
907 						NULL, 0, true, true), splitSpacing)
908 				.End()
909 				.Add(fLocalsTabView = new BTabView("locals view"))
910 			.End()
911 			.AddSplit(B_VERTICAL, splitSpacing)
912 				.GetSplitView(&fConsoleSplitView)
913 				.SetInsets(0.0)
914 				.Add(fConsoleOutputView = ConsoleOutputView::Create())
915 			.End()
916 		.End();
917 
918 	// add source view
919 	sourceScrollView->SetTarget(fSourceView = SourceView::Create(fTeam, this));
920 
921 	// add threads tab
922 	BSplitView* threadGroup = new BSplitView(B_HORIZONTAL, splitSpacing);
923 	threadGroup->SetName("Threads");
924 	fTabView->AddTab(threadGroup);
925 	BLayoutBuilder::Split<>(threadGroup)
926 		.GetSplitView(&fThreadSplitView)
927 		.Add(fThreadListView = ThreadListView::Create(fTeam, this))
928 		.Add(fStackTraceView = StackTraceView::Create(this));
929 
930 	// add images tab
931 	BSplitView* imagesGroup = new BSplitView(B_HORIZONTAL, splitSpacing);
932 	imagesGroup->SetName("Images");
933 	fTabView->AddTab(imagesGroup);
934 	BLayoutBuilder::Split<>(imagesGroup)
935 		.GetSplitView(&fImageSplitView)
936 		.Add(fImageListView = ImageListView::Create(fTeam, this))
937 		.Add(fImageFunctionsView = ImageFunctionsView::Create(this));
938 
939 	// add breakpoints tab
940 	BGroupView* breakpointsGroup = new BGroupView(B_HORIZONTAL,
941 		B_USE_SMALL_SPACING);
942 	breakpointsGroup->SetName("Breakpoints");
943 	fTabView->AddTab(breakpointsGroup);
944 	BLayoutBuilder::Group<>(breakpointsGroup)
945 //		.SetInsets(0.0f)
946 		.Add(fBreakpointsView = BreakpointsView::Create(fTeam, this));
947 
948 	// add local variables tab
949 	BView* tab = fVariablesView = VariablesView::Create(this);
950 	fLocalsTabView->AddTab(tab);
951 
952 	// add registers tab
953 	tab = fRegistersView = RegistersView::Create(fTeam->GetArchitecture());
954 	fLocalsTabView->AddTab(tab);
955 
956 	fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
957 	fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER));
958 	fStepIntoButton->SetMessage(new BMessage(MSG_THREAD_STEP_INTO));
959 	fStepOutButton->SetMessage(new BMessage(MSG_THREAD_STEP_OUT));
960 	fRunButton->SetTarget(this);
961 	fStepOverButton->SetTarget(this);
962 	fStepIntoButton->SetTarget(this);
963 	fStepOutButton->SetTarget(this);
964 
965 	fSourcePathView->SetExplicitMinSize(BSize(100.0, B_SIZE_UNSET));
966 	fSourcePathView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
967 	BMessageFilter* filter = new(std::nothrow) PathViewMessageFilter(
968 		BMessenger(this));
969 	if (filter != NULL)
970 		fSourcePathView->AddFilter(filter);
971 
972 	// add menus and menu items
973 	BMenu* menu = new BMenu("Team");
974 	fMenuBar->AddItem(menu);
975 	BMenuItem* item = new BMenuItem("Restart", new BMessage(
976 		MSG_TEAM_RESTART_REQUESTED), 'R', B_SHIFT_KEY);
977 	menu->AddItem(item);
978 	item->SetTarget(this);
979 	item = new BMenuItem("Close", new BMessage(B_QUIT_REQUESTED),
980 		'W');
981 	menu->AddItem(item);
982 	item->SetTarget(this);
983 	menu = new BMenu("Edit");
984 	fMenuBar->AddItem(menu);
985 	item = new BMenuItem("Copy", new BMessage(B_COPY), 'C');
986 	menu->AddItem(item);
987 	item->SetTarget(this);
988 	item = new BMenuItem("Select all", new BMessage(B_SELECT_ALL), 'A');
989 	menu->AddItem(item);
990 	item->SetTarget(this);
991 	menu = new BMenu("Tools");
992 	fMenuBar->AddItem(menu);
993 	item = new BMenuItem("Save debug report",
994 		new BMessage(MSG_CHOOSE_DEBUG_REPORT_LOCATION));
995 	menu->AddItem(item);
996 	item->SetTarget(this);
997 	item = new BMenuItem("Inspect memory",
998 		new BMessage(MSG_SHOW_INSPECTOR_WINDOW), 'I');
999 	menu->AddItem(item);
1000 	item->SetTarget(this);
1001 
1002 	AutoLocker< ::Team> locker(fTeam);
1003 	_UpdateRunButtons();
1004 }
1005 
1006 
1007 void
1008 TeamWindow::_SetActiveThread(::Thread* thread)
1009 {
1010 	if (thread == fActiveThread)
1011 		return;
1012 
1013 	if (fActiveThread != NULL)
1014 		fActiveThread->ReleaseReference();
1015 
1016 	fActiveThread = thread;
1017 
1018 	if (fActiveThread != NULL)
1019 		fActiveThread->AcquireReference();
1020 
1021 	AutoLocker< ::Team> locker(fTeam);
1022 	_UpdateRunButtons();
1023 
1024 	StackTrace* stackTrace = fActiveThread != NULL
1025 		? fActiveThread->GetStackTrace() : NULL;
1026 	BReference<StackTrace> stackTraceReference(stackTrace);
1027 		// hold a reference until we've set it
1028 
1029 	locker.Unlock();
1030 
1031 	fThreadListView->SetThread(fActiveThread);
1032 
1033 	_SetActiveStackTrace(stackTrace);
1034 	_UpdateCpuState();
1035 }
1036 
1037 
1038 void
1039 TeamWindow::_SetActiveImage(Image* image)
1040 {
1041 	if (image == fActiveImage)
1042 		return;
1043 
1044 	if (fActiveImage != NULL)
1045 		fActiveImage->ReleaseReference();
1046 
1047 	fActiveImage = image;
1048 
1049 	AutoLocker< ::Team> locker(fTeam);
1050 
1051 	ImageDebugInfo* imageDebugInfo = NULL;
1052 	BReference<ImageDebugInfo> imageDebugInfoReference;
1053 
1054 	if (fActiveImage != NULL) {
1055 		fActiveImage->AcquireReference();
1056 
1057 		imageDebugInfo = fActiveImage->GetImageDebugInfo();
1058 		imageDebugInfoReference.SetTo(imageDebugInfo);
1059 
1060 		// If the debug info is not loaded yet, request it.
1061 		if (fActiveImage->ImageDebugInfoState() == IMAGE_DEBUG_INFO_NOT_LOADED)
1062 			fListener->ImageDebugInfoRequested(fActiveImage);
1063 	}
1064 
1065 	locker.Unlock();
1066 
1067 	fImageListView->SetImage(fActiveImage);
1068 	fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
1069 }
1070 
1071 
1072 void
1073 TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace)
1074 {
1075 	delete fTraceUpdateRunner;
1076 	fTraceUpdateRunner = NULL;
1077 
1078 	if (stackTrace == fActiveStackTrace)
1079 		return;
1080 
1081 	if (fActiveStackTrace != NULL)
1082 		fActiveStackTrace->ReleaseReference();
1083 
1084 	fActiveStackTrace = stackTrace;
1085 
1086 	if (fActiveStackTrace != NULL)
1087 		fActiveStackTrace->AcquireReference();
1088 
1089 	fStackTraceView->SetStackTrace(fActiveStackTrace);
1090 	fSourceView->SetStackTrace(fActiveStackTrace, fActiveThread);
1091 
1092 	if (fActiveStackTrace != NULL)
1093 		_SetActiveStackFrame(fActiveStackTrace->FrameAt(0));
1094 	else
1095 		_SetActiveStackFrame(NULL);
1096 }
1097 
1098 
1099 void
1100 TeamWindow::_SetActiveStackFrame(StackFrame* frame)
1101 {
1102 	if (frame == fActiveStackFrame)
1103 		return;
1104 
1105 	if (fActiveStackFrame != NULL) {
1106 		AutoLocker< ::Team> locker(fTeam);
1107 		fActiveStackFrame->RemoveListener(this);
1108 		locker.Unlock();
1109 
1110 		fActiveStackFrame->ReleaseReference();
1111 	}
1112 
1113 	fActiveStackFrame = frame;
1114 
1115 	if (fActiveStackFrame != NULL) {
1116 		fActiveStackFrame->AcquireReference();
1117 
1118 		AutoLocker< ::Team> locker(fTeam);
1119 		fActiveStackFrame->AddListener(this);
1120 		locker.Unlock();
1121 
1122 		fActiveSourceObject = ACTIVE_SOURCE_STACK_FRAME;
1123 
1124 		_SetActiveFunction(fActiveStackFrame->Function());
1125 	}
1126 
1127 	_UpdateCpuState();
1128 
1129 	fStackTraceView->SetStackFrame(fActiveStackFrame);
1130 	if (fActiveStackFrame != NULL)
1131 		fVariablesView->SetStackFrame(fActiveThread, fActiveStackFrame);
1132 	else
1133 		fVariablesView->SetStackFrame(NULL, NULL);
1134 	fSourceView->SetStackFrame(fActiveStackFrame);
1135 }
1136 
1137 
1138 void
1139 TeamWindow::_SetActiveBreakpoint(UserBreakpoint* breakpoint)
1140 {
1141 	if (breakpoint == fActiveBreakpoint)
1142 		return;
1143 
1144 	if (fActiveBreakpoint != NULL)
1145 		fActiveBreakpoint->ReleaseReference();
1146 
1147 	fActiveBreakpoint = breakpoint;
1148 
1149 	if (fActiveBreakpoint != NULL) {
1150 		fActiveBreakpoint->AcquireReference();
1151 
1152 		// get the breakpoint's function (more exactly: some function instance)
1153 		AutoLocker< ::Team> locker(fTeam);
1154 
1155 		Function* function = fTeam->FunctionByID(
1156 			breakpoint->Location().GetFunctionID());
1157 		FunctionInstance* functionInstance = function != NULL
1158 			? function->FirstInstance() : NULL;
1159 		BReference<FunctionInstance> functionInstanceReference(
1160 			functionInstance);
1161 
1162 		locker.Unlock();
1163 
1164 		fActiveSourceObject = ACTIVE_SOURCE_BREAKPOINT;
1165 
1166 		_SetActiveFunction(functionInstance);
1167 
1168 		// scroll to the breakpoint's source code line number (it is not done
1169 		// automatically, if the active function remains the same)
1170 		_ScrollToActiveFunction();
1171 	}
1172 }
1173 
1174 
1175 void
1176 TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance)
1177 {
1178 	if (functionInstance == fActiveFunction)
1179 		return;
1180 
1181 	AutoLocker< ::Team> locker(fTeam);
1182 
1183 	if (fActiveFunction != NULL) {
1184 		fActiveFunction->GetFunction()->RemoveListener(this);
1185 		fActiveFunction->ReleaseReference();
1186 	}
1187 
1188 	// to avoid listener feedback problems, first unset the active function and
1189 	// set the new image, if any
1190 	locker.Unlock();
1191 
1192 	fActiveFunction = NULL;
1193 
1194 	if (functionInstance != NULL)
1195 		_SetActiveImage(fTeam->ImageByAddress(functionInstance->Address()));
1196 
1197 	fActiveFunction = functionInstance;
1198 
1199 	locker.Lock();
1200 
1201 	SourceCode* sourceCode = NULL;
1202 	BReference<SourceCode> sourceCodeReference;
1203 
1204 	if (fActiveFunction != NULL) {
1205 		fActiveFunction->AcquireReference();
1206 		fActiveFunction->GetFunction()->AddListener(this);
1207 
1208 		Function* function = fActiveFunction->GetFunction();
1209 		sourceCode = function->GetSourceCode();
1210 		if (sourceCode == NULL)
1211 			sourceCode = fActiveFunction->GetSourceCode();
1212 		sourceCodeReference.SetTo(sourceCode);
1213 
1214 		// If the source code is not loaded yet, request it.
1215 		if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED)
1216 			fListener->FunctionSourceCodeRequested(fActiveFunction);
1217 	}
1218 
1219 	locker.Unlock();
1220 
1221 	_SetActiveSourceCode(sourceCode);
1222 
1223 	fImageFunctionsView->SetFunction(fActiveFunction);
1224 
1225 	locker.Lock();
1226 
1227 	// look if our current stack trace has a frame matching the selected
1228 	// function. If so, set it to match.
1229 	StackFrame* matchingFrame = NULL;
1230 	BReference<StackFrame> frameRef;
1231 
1232 	if (fActiveStackTrace != NULL) {
1233 		for (int32 i = 0; i < fActiveStackTrace->CountFrames(); i++) {
1234 			StackFrame* frame = fActiveStackTrace->FrameAt(i);
1235 			if (frame->Function() == fActiveFunction) {
1236 				matchingFrame = frame;
1237 				frameRef.SetTo(frame);
1238 				break;
1239 			}
1240 		}
1241 	}
1242 
1243 	locker.Unlock();
1244 
1245 	if (matchingFrame != NULL)
1246 		_SetActiveStackFrame(matchingFrame);
1247 }
1248 
1249 
1250 void
1251 TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
1252 {
1253 	if (sourceCode == fActiveSourceCode) {
1254 		_ScrollToActiveFunction();
1255 		return;
1256 	}
1257 
1258 	if (fActiveSourceCode != NULL)
1259 		fActiveSourceCode->ReleaseReference();
1260 
1261 	fActiveSourceCode = sourceCode;
1262 
1263 	if (fActiveSourceCode != NULL)
1264 		fActiveSourceCode->AcquireReference();
1265 
1266 	fSourceView->SetSourceCode(fActiveSourceCode);
1267 
1268 	_UpdateSourcePathState();
1269 	_ScrollToActiveFunction();
1270 }
1271 
1272 void
1273 TeamWindow::_UpdateCpuState()
1274 {
1275 	// get the CPU state
1276 	CpuState* cpuState = NULL;
1277 	BReference<CpuState> cpuStateReference;
1278 		// hold a reference until the register view has one
1279 
1280 	if (fActiveThread != NULL) {
1281 		// Get the CPU state from the active stack frame or the thread directly.
1282 		if (fActiveStackFrame == NULL) {
1283 			AutoLocker< ::Team> locker(fTeam);
1284 			cpuState = fActiveThread->GetCpuState();
1285 			cpuStateReference.SetTo(cpuState);
1286 			locker.Unlock();
1287 		} else
1288 			cpuState = fActiveStackFrame->GetCpuState();
1289 	}
1290 
1291 	fRegistersView->SetCpuState(cpuState);
1292 }
1293 
1294 
1295 void
1296 TeamWindow::_UpdateRunButtons()
1297 {
1298 	uint32 threadState = fActiveThread != NULL
1299 		? fActiveThread->State() : THREAD_STATE_UNKNOWN;
1300 
1301 	switch (threadState) {
1302 		case THREAD_STATE_UNKNOWN:
1303 			fRunButton->SetEnabled(false);
1304 			fStepOverButton->SetEnabled(false);
1305 			fStepIntoButton->SetEnabled(false);
1306 			fStepOutButton->SetEnabled(false);
1307 			break;
1308 		case THREAD_STATE_RUNNING:
1309 			if (fTraceUpdateRunner == NULL) {
1310 				fRunButton->SetLabel("Debug");
1311 				fRunButton->SetMessage(new BMessage(MSG_THREAD_STOP));
1312 				fRunButton->SetEnabled(true);
1313 				fStepOverButton->SetEnabled(false);
1314 				fStepIntoButton->SetEnabled(false);
1315 				fStepOutButton->SetEnabled(false);
1316 			}
1317 			break;
1318 		case THREAD_STATE_STOPPED:
1319 			fRunButton->SetLabel("Run");
1320 			fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
1321 			fRunButton->SetEnabled(true);
1322 			fStepOverButton->SetEnabled(true);
1323 			fStepIntoButton->SetEnabled(true);
1324 			fStepOutButton->SetEnabled(true);
1325 			break;
1326 	}
1327 }
1328 
1329 
1330 void
1331 TeamWindow::_UpdateSourcePathState()
1332 {
1333 	LocatableFile* sourceFile = NULL;
1334 	BString sourceText = "Source file unavailable.";
1335 	BString truncatedText;
1336 
1337 	if (fActiveSourceCode != NULL) {
1338 		sourceFile = fActiveFunction->GetFunctionDebugInfo()->SourceFile();
1339 
1340 		if (sourceFile != NULL && !sourceFile->GetLocatedPath(sourceText))
1341 			sourceFile->GetPath(sourceText);
1342 
1343 		if (fActiveFunction->GetFunction()->SourceCodeState()
1344 			!= FUNCTION_SOURCE_NOT_LOADED
1345 			&& fActiveSourceCode->GetSourceFile() == NULL
1346 			&& sourceFile != NULL) {
1347 			sourceText.Prepend("Click to locate source file '");
1348 			sourceText += "'";
1349 			truncatedText = sourceText;
1350 			fSourcePathView->TruncateString(&truncatedText, B_TRUNCATE_MIDDLE,
1351 				fSourcePathView->Bounds().Width());
1352 		} else if (sourceFile != NULL)
1353 			sourceText.Prepend("File: ");
1354 	}
1355 
1356 	if (!truncatedText.IsEmpty() && truncatedText != sourceText) {
1357 		fSourcePathView->SetToolTip(sourceText);
1358 		fSourcePathView->SetText(truncatedText);
1359 	} else
1360 		fSourcePathView->SetText(sourceText);
1361 }
1362 
1363 
1364 void
1365 TeamWindow::_ScrollToActiveFunction()
1366 {
1367 	// Scroll to the active function, if it has been selected manually.
1368 	if (fActiveFunction == NULL || fActiveSourceCode == NULL)
1369 		return;
1370 
1371 	switch (fActiveSourceObject) {
1372 		case ACTIVE_SOURCE_FUNCTION:
1373 			fSourceView->ScrollToAddress(fActiveFunction->Address());
1374 			break;
1375 		case ACTIVE_SOURCE_BREAKPOINT:
1376 		{
1377 			if (fActiveBreakpoint == NULL)
1378 				break;
1379 
1380 			const UserBreakpointLocation& location
1381 				= fActiveBreakpoint->Location();
1382 			int32 line = location.GetSourceLocation().Line();
1383 
1384 			if (location.SourceFile() != NULL && line >= 0
1385 				&& fActiveSourceCode->GetSourceFile()
1386 					== location.SourceFile()) {
1387 				fSourceView->ScrollToLine(line);
1388 			} else {
1389 				fSourceView->ScrollToAddress(
1390 					fActiveFunction->Address()
1391 						+ location.RelativeAddress());
1392 			}
1393 			break;
1394 		}
1395 		case ACTIVE_SOURCE_NONE:
1396 		case ACTIVE_SOURCE_STACK_FRAME:
1397 			break;
1398 	}
1399 }
1400 
1401 
1402 void
1403 TeamWindow::_HandleThreadStateChanged(thread_id threadID)
1404 {
1405 	AutoLocker< ::Team> locker(fTeam);
1406 
1407 	::Thread* thread = fTeam->ThreadByID(threadID);
1408 	if (thread == NULL)
1409 		return;
1410 
1411 	// If the thread has been stopped and we don't have an active thread yet
1412 	// (or it isn't stopped), switch to this thread. Otherwise ignore the event.
1413 	if (thread->State() == THREAD_STATE_STOPPED
1414 		&& (fActiveThread == NULL
1415 			|| (thread != fActiveThread
1416 				&& fActiveThread->State() != THREAD_STATE_STOPPED))) {
1417 		_SetActiveThread(thread);
1418 	} else if (thread != fActiveThread) {
1419 		// otherwise ignore the event, if the thread is not the active one
1420 		return;
1421 	}
1422 
1423 	// Switch to the threads tab view when the thread has stopped.
1424 	if (thread->State() == THREAD_STATE_STOPPED) {
1425 		fTabView->Select(MAIN_TAB_INDEX_THREADS);
1426 
1427 		// if we hit a breakpoint or exception, raise the window to the
1428 		// foreground, since if this occurs while e.g. debugging a GUI
1429 		// app, it might not be immediately obvious that such an event
1430 		// occurred as the app may simply appear to hang.
1431 		Activate();
1432 	}
1433 
1434 	_UpdateRunButtons();
1435 }
1436 
1437 
1438 void
1439 TeamWindow::_HandleCpuStateChanged(thread_id threadID)
1440 {
1441 	// We're only interested in the currently selected thread
1442 	if (fActiveThread == NULL || threadID != fActiveThread->ID())
1443 		return;
1444 
1445 	_UpdateCpuState();
1446 }
1447 
1448 
1449 void
1450 TeamWindow::_HandleStackTraceChanged(thread_id threadID)
1451 {
1452 	// We're only interested in the currently selected thread
1453 	if (fActiveThread == NULL || threadID != fActiveThread->ID())
1454 		return;
1455 
1456 	AutoLocker< ::Team> locker(fTeam);
1457 
1458 	StackTrace* stackTrace = fActiveThread != NULL
1459 		? fActiveThread->GetStackTrace() : NULL;
1460 	BReference<StackTrace> stackTraceReference(stackTrace);
1461 		// hold a reference until the register view has one
1462 
1463 	locker.Unlock();
1464 
1465 	if (stackTrace == NULL) {
1466 		if (fTraceUpdateRunner != NULL)
1467 			return;
1468 
1469 		BMessage message(MSG_CLEAR_STACK_TRACE);
1470 		fTraceUpdateRunner = new(std::nothrow) BMessageRunner(this,
1471 			message, 250000, 1);
1472 		if (fTraceUpdateRunner != NULL
1473 			&& fTraceUpdateRunner->InitCheck() == B_OK) {
1474 			fStackTraceView->SetStackTraceClearPending();
1475 			fVariablesView->SetStackFrameClearPending();
1476 			return;
1477 		}
1478 	}
1479 
1480 	_SetActiveStackTrace(stackTrace);
1481 }
1482 
1483 
1484 void
1485 TeamWindow::_HandleImageDebugInfoChanged(image_id imageID)
1486 {
1487 	TRACE_GUI("TeamWindow::_HandleImageDebugInfoChanged(%" B_PRId32 ")\n",
1488 		imageID);
1489 
1490 	// We're only interested in the currently selected thread
1491 	if (fActiveImage == NULL || imageID != fActiveImage->ID())
1492 		return;
1493 
1494 	AutoLocker< ::Team> locker(fTeam);
1495 
1496 	ImageDebugInfo* imageDebugInfo = fActiveImage != NULL
1497 		? fActiveImage->GetImageDebugInfo() : NULL;
1498 
1499 	TRACE_GUI("  image debug info: %p\n", imageDebugInfo);
1500 
1501 	BReference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo);
1502 		// hold a reference until we've set it
1503 
1504 	locker.Unlock();
1505 
1506 	fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
1507 }
1508 
1509 
1510 void
1511 TeamWindow::_HandleSourceCodeChanged()
1512 {
1513 	// If we don't have an active function anymore, the message is obsolete.
1514 	if (fActiveFunction == NULL)
1515 		return;
1516 
1517 	// get a reference to the source code
1518 	AutoLocker< ::Team> locker(fTeam);
1519 
1520 	SourceCode* sourceCode = NULL;
1521 	if (fActiveFunction->GetFunction()->SourceCodeState()
1522 		== FUNCTION_SOURCE_LOADED) {
1523 		sourceCode = fActiveFunction->GetFunction()->GetSourceCode();
1524 	} else
1525 		sourceCode = fActiveFunction->GetSourceCode();
1526 
1527 	BReference<SourceCode> sourceCodeReference(sourceCode);
1528 
1529 	locker.Unlock();
1530 
1531 	_SetActiveSourceCode(sourceCode);
1532 }
1533 
1534 
1535 void
1536 TeamWindow::_HandleUserBreakpointChanged(UserBreakpoint* breakpoint)
1537 {
1538 	fSourceView->UserBreakpointChanged(breakpoint);
1539 	fBreakpointsView->UserBreakpointChanged(breakpoint);
1540 }
1541 
1542 
1543 void
1544 TeamWindow::_HandleWatchpointChanged(Watchpoint* watchpoint)
1545 {
1546 	fBreakpointsView->WatchpointChanged(watchpoint);
1547 }
1548 
1549 
1550 status_t
1551 TeamWindow::_RetrieveMatchingSourceWorker(void* arg)
1552 {
1553 	TeamWindow* window = (TeamWindow*)arg;
1554 
1555 	BStringList* entries = new(std::nothrow) BStringList();
1556 	if (entries == NULL)
1557 		return B_NO_MEMORY;
1558 	ObjectDeleter<BStringList> stringListDeleter(entries);
1559 
1560 	if (!window->Lock())
1561 		return B_BAD_VALUE;
1562 
1563 	BString path;
1564 	window->fActiveFunction->GetFunctionDebugInfo()->SourceFile()
1565 		->GetPath(path);
1566 	window->Unlock();
1567 
1568 	status_t error = window->_RetrieveMatchingSourceEntries(path, entries);
1569 	if (error != B_OK)
1570 		return error;
1571 
1572 	entries->Sort();
1573 	BMessenger messenger(window);
1574 	if (messenger.IsValid() && messenger.LockTarget()) {
1575 		if (window->fActiveSourceWorker == find_thread(NULL)) {
1576 			BMessage message(MSG_SOURCE_ENTRY_QUERY_COMPLETE);
1577 			message.AddPointer("entries", entries);
1578 			if (messenger.SendMessage(&message) == B_OK)
1579 				stringListDeleter.Detach();
1580 		}
1581 		window->Unlock();
1582 	}
1583 
1584 	return B_OK;
1585 }
1586 
1587 
1588 void
1589 TeamWindow::_HandleResolveMissingSourceFile(entry_ref& locatedPath)
1590 {
1591 	if (fActiveFunction != NULL) {
1592 		LocatableFile* sourceFile = fActiveFunction->GetFunctionDebugInfo()
1593 			->SourceFile();
1594 		if (sourceFile != NULL) {
1595 			BString sourcePath;
1596 			sourceFile->GetPath(sourcePath);
1597 			BString sourceFileName(sourcePath);
1598 			int32 index = sourcePath.FindLast('/');
1599 			if (index >= 0)
1600 				sourceFileName.Remove(0, index + 1);
1601 
1602 			BPath targetFilePath(&locatedPath);
1603 			if (targetFilePath.InitCheck() != B_OK)
1604 				return;
1605 
1606 			if (strcmp(sourceFileName.String(), targetFilePath.Leaf()) != 0) {
1607 				BString message;
1608 				message.SetToFormat("The names of source file '%s' and located"
1609 					" file '%s' differ. Use file anyway?",
1610 					sourceFileName.String(), targetFilePath.Leaf());
1611 				BAlert* alert = new(std::nothrow) BAlert(
1612 					"Source path mismatch", message.String(), "Cancel", "Use");
1613 				if (alert == NULL)
1614 					return;
1615 
1616 				int32 choice = alert->Go();
1617 				if (choice <= 0)
1618 					return;
1619 			}
1620 			fListener->SourceEntryLocateRequested(sourcePath,
1621 				targetFilePath.Path());
1622 			fListener->FunctionSourceCodeRequested(fActiveFunction);
1623 		}
1624 	}
1625 }
1626 
1627 
1628 void
1629 TeamWindow::_HandleLocateSourceRequest(BStringList* entries)
1630 {
1631 	if (fActiveFunction == NULL)
1632 		return;
1633 	else if (fActiveFunction->GetFunctionDebugInfo()->SourceFile() == NULL)
1634 		return;
1635 	else if (fActiveSourceCode == NULL)
1636 		return;
1637 	else if (fActiveSourceCode->GetSourceFile() != NULL)
1638 		return;
1639 	else if (fActiveFunction->GetFunction()->SourceCodeState()
1640 		== FUNCTION_SOURCE_NOT_LOADED) {
1641 		return;
1642 	}
1643 
1644 	if (entries == NULL) {
1645 		if (fActiveSourceWorker < 0) {
1646 			fActiveSourceWorker = spawn_thread(&_RetrieveMatchingSourceWorker,
1647 				"source file query worker", B_NORMAL_PRIORITY, this);
1648 			if (fActiveSourceWorker > 0)
1649 				resume_thread(fActiveSourceWorker);
1650 		}
1651 		return;
1652 	}
1653 
1654 	int32 count = entries->CountStrings();
1655 	if (count > 0) {
1656 		BPopUpMenu* menu = new(std::nothrow) BPopUpMenu("");
1657 		if (menu == NULL)
1658 			return;
1659 
1660 		BPrivate::ObjectDeleter<BPopUpMenu> menuDeleter(menu);
1661 		BMenuItem* item = NULL;
1662 		for (int32 i = 0; i < count; i++) {
1663 			item = new(std::nothrow) BMenuItem(entries->StringAt(i).String(),
1664 				NULL);
1665 			if (item == NULL || !menu->AddItem(item)) {
1666 				delete item;
1667 				return;
1668 			}
1669 		}
1670 
1671 		menu->AddSeparatorItem();
1672 		BMenuItem* manualItem = new(std::nothrow) BMenuItem(
1673 			"Locate manually" B_UTF8_ELLIPSIS, NULL);
1674 		if (manualItem == NULL || !menu->AddItem(manualItem)) {
1675 			delete manualItem;
1676 			return;
1677 		}
1678 
1679 		BPoint point;
1680 		fSourcePathView->GetMouse(&point, NULL, false);
1681 		fSourcePathView->ConvertToScreen(&point);
1682 		item = menu->Go(point, false, true);
1683 		if (item == NULL)
1684 			return;
1685 		else if (item != manualItem) {
1686 			// if the user picks to locate the entry manually,
1687 			// then fall through to the usual file panel logic
1688 			// as if we'd found no matches at all.
1689 			entry_ref ref;
1690 			if (get_ref_for_path(item->Label(), &ref) == B_OK) {
1691 				_HandleResolveMissingSourceFile(ref);
1692 				return;
1693 			}
1694 		}
1695 	}
1696 
1697 	try {
1698 		if (fFilePanel == NULL) {
1699 			fFilePanel = new BFilePanel(B_OPEN_PANEL,
1700 				new BMessenger(this));
1701 		}
1702 		fFilePanel->Show();
1703 	} catch (...) {
1704 		delete fFilePanel;
1705 		fFilePanel = NULL;
1706 	}
1707 }
1708 
1709 
1710 status_t
1711 TeamWindow::_RetrieveMatchingSourceEntries(const BString& path,
1712 	BStringList* _entries)
1713 {
1714 	BPath filePath(path);
1715 	status_t error = filePath.InitCheck();
1716 	if (error != B_OK)
1717 		return error;
1718 
1719 	_entries->MakeEmpty();
1720 
1721 	BQuery query;
1722 	BString predicate;
1723 	query.PushAttr("name");
1724 	query.PushString(filePath.Leaf());
1725 	query.PushOp(B_EQ);
1726 
1727 	error = query.GetPredicate(&predicate);
1728 	if (error != B_OK)
1729 		return error;
1730 
1731 	BVolumeRoster roster;
1732 	BVolume volume;
1733 	while (roster.GetNextVolume(&volume) == B_OK) {
1734 		if (!volume.KnowsQuery())
1735 			continue;
1736 
1737 		if (query.SetVolume(&volume) != B_OK)
1738 			continue;
1739 
1740 		error = query.SetPredicate(predicate.String());
1741 		if (error != B_OK)
1742 			continue;
1743 
1744 		if (query.Fetch() != B_OK)
1745 			continue;
1746 
1747 		entry_ref ref;
1748 		while (query.GetNextRef(&ref) == B_OK) {
1749 			filePath.SetTo(&ref);
1750 			_entries->Add(filePath.Path());
1751 		}
1752 
1753 		query.Clear();
1754 	}
1755 
1756 	return B_OK;
1757 }
1758 
1759 
1760 status_t
1761 TeamWindow::_SaveInspectorSettings(const BMessage* settings)
1762 {
1763 	if (fUiSettings.AddSettings("inspectorWindow", *settings) != B_OK)
1764 		return B_NO_MEMORY;
1765 
1766 	return B_OK;
1767 }
1768