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