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