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