1 /* 2 * Copyright 2015, Rene Gollent, rene@gollent.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ReportUserInterface.h" 8 9 #include <stdio.h> 10 11 #include <Entry.h> 12 #include <FindDirectory.h> 13 #include <Path.h> 14 15 #include <AutoLocker.h> 16 17 #include "MessageCodes.h" 18 #include "UiUtils.h" 19 20 21 ReportUserInterface::ReportUserInterface(thread_id targetThread, 22 const char* reportPath) 23 : 24 fTeam(NULL), 25 fListener(NULL), 26 fTargetThread(targetThread), 27 fReportPath(reportPath), 28 fShowSemaphore(-1), 29 fReportSemaphore(-1), 30 fShown(false), 31 fTerminating(false) 32 { 33 } 34 35 36 ReportUserInterface::~ReportUserInterface() 37 { 38 if (fShowSemaphore >= 0) 39 delete_sem(fShowSemaphore); 40 41 fTeam->RemoveListener(this); 42 } 43 44 45 const char* 46 ReportUserInterface::ID() const 47 { 48 return "ReportUserInterface"; 49 } 50 51 52 status_t 53 ReportUserInterface::Init(Team* team, UserInterfaceListener* listener) 54 { 55 fShowSemaphore = create_sem(0, "show report"); 56 if (fShowSemaphore < 0) 57 return fShowSemaphore; 58 59 fReportSemaphore = create_sem(0, "report generator wait"); 60 if (fReportSemaphore < 0) 61 return fReportSemaphore; 62 63 fTeam = team; 64 fListener = listener; 65 66 fTeam->AddListener(this); 67 68 return B_OK; 69 } 70 71 72 void 73 ReportUserInterface::Show() 74 { 75 fShown = true; 76 release_sem(fShowSemaphore); 77 } 78 79 80 void 81 ReportUserInterface::Terminate() 82 { 83 fTerminating = true; 84 } 85 86 87 bool 88 ReportUserInterface::IsInteractive() const 89 { 90 return false; 91 } 92 93 94 status_t 95 ReportUserInterface::LoadSettings(const TeamUiSettings* settings) 96 { 97 return B_OK; 98 } 99 100 101 status_t 102 ReportUserInterface::SaveSettings(TeamUiSettings*& settings) const 103 { 104 return B_OK; 105 } 106 107 108 void 109 ReportUserInterface::NotifyUser(const char* title, const char* message, 110 user_notification_type type) 111 { 112 } 113 114 115 void 116 ReportUserInterface::NotifyBackgroundWorkStatus(const char* message) 117 { 118 } 119 120 121 int32 122 ReportUserInterface::SynchronouslyAskUser(const char* title, 123 const char* message, const char* choice1, const char* choice2, 124 const char* choice3) 125 { 126 return -1; 127 } 128 129 130 status_t 131 ReportUserInterface::SynchronouslyAskUserForFile(entry_ref* _ref) 132 { 133 return B_UNSUPPORTED; 134 } 135 136 137 void 138 ReportUserInterface::Run() 139 { 140 // Wait for the Show() semaphore to be released. 141 status_t error; 142 do { 143 error = acquire_sem(fShowSemaphore); 144 } while (error == B_INTERRUPTED); 145 146 if (error != B_OK) 147 return; 148 149 bool waitNeeded = false; 150 if (fTargetThread > 0) { 151 AutoLocker< ::Team> teamLocker(fTeam); 152 ::Thread* thread = fTeam->ThreadByID(fTargetThread); 153 if (thread == NULL) 154 waitNeeded = true; 155 else if (thread->State() != THREAD_STATE_STOPPED) { 156 waitNeeded = true; 157 fListener->ThreadActionRequested(fTargetThread, MSG_THREAD_STOP); 158 } 159 } 160 161 if (waitNeeded) { 162 do { 163 error = acquire_sem(fShowSemaphore); 164 } while (error == B_INTERRUPTED); 165 166 if (error != B_OK) 167 return; 168 } 169 170 entry_ref ref; 171 if (fReportPath != NULL && fReportPath[0] == '/') { 172 error = get_ref_for_path(fReportPath, &ref); 173 } else { 174 char filename[B_FILE_NAME_LENGTH]; 175 if (fReportPath != NULL) 176 strlcpy(filename, fReportPath, sizeof(filename)); 177 else 178 UiUtils::ReportNameForTeam(fTeam, filename, sizeof(filename)); 179 180 BPath path; 181 error = find_directory(B_DESKTOP_DIRECTORY, &path); 182 if (error == B_OK) 183 error = path.Append(filename); 184 if (error == B_OK) 185 error = get_ref_for_path(path.Path(), &ref); 186 } 187 188 if (error != B_OK) 189 printf("Unable to get ref for report path %s\n", strerror(error)); 190 else { 191 fListener->DebugReportRequested(&ref); 192 193 do { 194 error = acquire_sem(fReportSemaphore); 195 } while (error == B_INTERRUPTED); 196 } 197 198 fListener->UserInterfaceQuitRequested( 199 UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM); 200 } 201 202 203 void 204 ReportUserInterface::ThreadAdded(const Team::ThreadEvent& event) 205 { 206 ::Thread* thread = event.GetThread(); 207 if (thread->ID() != fTargetThread) 208 return; 209 210 if (thread->State() != THREAD_STATE_STOPPED) 211 fListener->ThreadActionRequested(thread->ID(), MSG_THREAD_STOP); 212 else 213 release_sem(fShowSemaphore); 214 } 215 216 217 void 218 ReportUserInterface::ThreadStateChanged(const Team::ThreadEvent& event) 219 { 220 ::Thread* thread = event.GetThread(); 221 if (thread->ID() != fTargetThread) 222 return; 223 else if (thread->State() == THREAD_STATE_STOPPED) 224 release_sem(fShowSemaphore); 225 } 226 227 228 void 229 ReportUserInterface::DebugReportChanged(const Team::DebugReportEvent& event) 230 { 231 printf("Debug report saved to %s\n", event.GetReportPath()); 232 release_sem(fReportSemaphore); 233 } 234