1/* 2 * Copyright 2015-2016, 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 21ReportUserInterface::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 36ReportUserInterface::~ReportUserInterface() 37{ 38 if (fShowSemaphore >= 0) 39 delete_sem(fShowSemaphore); 40 41 if (fTeam != NULL) 42 fTeam->RemoveListener(this); 43} 44 45 46const char* 47ReportUserInterface::ID() const 48{ 49 return "ReportUserInterface"; 50} 51 52 53status_t 54ReportUserInterface::Init(Team* team, UserInterfaceListener* listener) 55{ 56 fShowSemaphore = create_sem(0, "show report"); 57 if (fShowSemaphore < 0) 58 return fShowSemaphore; 59 60 fReportSemaphore = create_sem(0, "report generator wait"); 61 if (fReportSemaphore < 0) 62 return fReportSemaphore; 63 64 fTeam = team; 65 fListener = listener; 66 67 fTeam->AddListener(this); 68 69 return B_OK; 70} 71 72 73void 74ReportUserInterface::Show() 75{ 76 fShown = true; 77 release_sem(fShowSemaphore); 78} 79 80 81void 82ReportUserInterface::Terminate() 83{ 84 fTerminating = true; 85} 86 87 88UserInterface* 89ReportUserInterface::Clone() const 90{ 91 // the report interface does not support cloning, since 92 // it won't ever be asked to interactively restart. 93 return NULL; 94} 95 96 97bool 98ReportUserInterface::IsInteractive() const 99{ 100 return false; 101} 102 103 104status_t 105ReportUserInterface::LoadSettings(const TeamUiSettings* settings) 106{ 107 return B_OK; 108} 109 110 111status_t 112ReportUserInterface::SaveSettings(TeamUiSettings*& settings) const 113{ 114 return B_OK; 115} 116 117 118void 119ReportUserInterface::NotifyUser(const char* title, const char* message, 120 user_notification_type type) 121{ 122} 123 124 125void 126ReportUserInterface::NotifyBackgroundWorkStatus(const char* message) 127{ 128} 129 130 131int32 132ReportUserInterface::SynchronouslyAskUser(const char* title, 133 const char* message, const char* choice1, const char* choice2, 134 const char* choice3) 135{ 136 return -1; 137} 138 139 140status_t 141ReportUserInterface::SynchronouslyAskUserForFile(entry_ref* _ref) 142{ 143 return B_UNSUPPORTED; 144} 145 146 147void 148ReportUserInterface::Run() 149{ 150 // Wait for the Show() semaphore to be released. 151 status_t error; 152 do { 153 error = acquire_sem(fShowSemaphore); 154 } while (error == B_INTERRUPTED); 155 156 if (error != B_OK) 157 return; 158 159 bool waitNeeded = false; 160 if (fTargetThread > 0) { 161 AutoLocker< ::Team> teamLocker(fTeam); 162 ::Thread* thread = fTeam->ThreadByID(fTargetThread); 163 if (thread == NULL) 164 waitNeeded = true; 165 else if (thread->State() != THREAD_STATE_STOPPED) { 166 waitNeeded = true; 167 fListener->ThreadActionRequested(fTargetThread, MSG_THREAD_STOP); 168 } 169 } 170 171 if (waitNeeded) { 172 do { 173 error = acquire_sem(fShowSemaphore); 174 } while (error == B_INTERRUPTED); 175 176 if (error != B_OK) 177 return; 178 } 179 180 entry_ref ref; 181 if (fReportPath != NULL && fReportPath[0] == '/') { 182 error = get_ref_for_path(fReportPath, &ref); 183 } else { 184 char filename[B_FILE_NAME_LENGTH]; 185 if (fReportPath != NULL) 186 strlcpy(filename, fReportPath, sizeof(filename)); 187 else 188 UiUtils::ReportNameForTeam(fTeam, filename, sizeof(filename)); 189 190 BPath path; 191 error = find_directory(B_DESKTOP_DIRECTORY, &path); 192 if (error == B_OK) 193 error = path.Append(filename); 194 if (error == B_OK) 195 error = get_ref_for_path(path.Path(), &ref); 196 } 197 198 if (error != B_OK) 199 printf("Unable to get ref for report path %s\n", strerror(error)); 200 else { 201 fListener->DebugReportRequested(&ref); 202 203 do { 204 error = acquire_sem(fReportSemaphore); 205 } while (error == B_INTERRUPTED); 206 } 207 208 fListener->UserInterfaceQuitRequested( 209 UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM); 210} 211 212 213void 214ReportUserInterface::ThreadAdded(const Team::ThreadEvent& event) 215{ 216 ::Thread* thread = event.GetThread(); 217 if (thread->ID() != fTargetThread) 218 return; 219 220 if (thread->State() != THREAD_STATE_STOPPED) 221 fListener->ThreadActionRequested(thread->ID(), MSG_THREAD_STOP); 222 else 223 release_sem(fShowSemaphore); 224} 225 226 227void 228ReportUserInterface::ThreadStateChanged(const Team::ThreadEvent& event) 229{ 230 ::Thread* thread = event.GetThread(); 231 if (thread->ID() != fTargetThread) 232 return; 233 else if (thread->State() == THREAD_STATE_STOPPED) 234 release_sem(fShowSemaphore); 235} 236 237 238void 239ReportUserInterface::DebugReportChanged(const Team::DebugReportEvent& event) 240{ 241 if (event.GetFinalStatus() == B_OK) 242 printf("Debug report saved to %s\n", event.GetReportPath()); 243 else { 244 fprintf(stderr, "Failed to write debug report: %s\n", strerror( 245 event.GetFinalStatus())); 246 } 247 release_sem(fReportSemaphore); 248} 249