1 /* 2 * Copyright 2013, Stephan Aßmus <superstippi@gmx.de>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "App.h" 8 9 #include <stdio.h> 10 11 #include <Alert.h> 12 #include <Catalog.h> 13 #include <Entry.h> 14 #include <Message.h> 15 #include <package/PackageInfo.h> 16 #include <Path.h> 17 #include <Roster.h> 18 #include <Screen.h> 19 #include <String.h> 20 21 #include "support.h" 22 23 #include "FeaturedPackagesView.h" 24 #include "MainWindow.h" 25 26 27 #undef B_TRANSLATION_CONTEXT 28 #define B_TRANSLATION_CONTEXT "App" 29 30 31 App::App() 32 : 33 BApplication("application/x-vnd.Haiku-HaikuDepot"), 34 fMainWindow(NULL), 35 fWindowCount(0), 36 fSettingsRead(false) 37 { 38 _CheckPackageDaemonRuns(); 39 } 40 41 42 App::~App() 43 { 44 // We cannot let global destructors cleanup static BitmapRef objects, 45 // since calling BBitmap destructors needs a valid BApplication still 46 // around. That's why we do it here. 47 PackageInfo::CleanupDefaultIcon(); 48 FeaturedPackagesView::CleanupIcons(); 49 } 50 51 52 bool 53 App::QuitRequested() 54 { 55 if (fMainWindow != NULL 56 && fMainWindow->LockLooperWithTimeout(1500000) == B_OK) { 57 BMessage windowSettings; 58 fMainWindow->StoreSettings(windowSettings); 59 60 fMainWindow->UnlockLooper(); 61 62 _StoreSettings(windowSettings); 63 } 64 65 return true; 66 } 67 68 69 void 70 App::ReadyToRun() 71 { 72 if (fWindowCount > 0) 73 return; 74 75 BMessage settings; 76 _LoadSettings(settings); 77 78 fMainWindow = new MainWindow(settings); 79 _ShowWindow(fMainWindow); 80 } 81 82 83 void 84 App::MessageReceived(BMessage* message) 85 { 86 switch (message->what) { 87 case MSG_MAIN_WINDOW_CLOSED: 88 { 89 BMessage windowSettings; 90 if (message->FindMessage("window settings", 91 &windowSettings) == B_OK) { 92 _StoreSettings(windowSettings); 93 } 94 95 fWindowCount--; 96 if (fWindowCount == 0) 97 Quit(); 98 break; 99 } 100 101 default: 102 BApplication::MessageReceived(message); 103 break; 104 } 105 } 106 107 108 void 109 App::RefsReceived(BMessage* message) 110 { 111 entry_ref ref; 112 int32 index = 0; 113 while (message->FindRef("refs", index++, &ref) == B_OK) { 114 BEntry entry(&ref, true); 115 _Open(entry); 116 } 117 } 118 119 120 void 121 App::ArgvReceived(int32 argc, char* argv[]) 122 { 123 for (int i = 1; i < argc;) { 124 if (0 == strcmp("--webappbaseurl", argv[i])) { 125 if (i == argc-1) { 126 fprintf(stderr, "unexpected end of arguments; missing web app base url\n"); 127 Quit(); 128 } 129 130 if (WebAppInterface::SetBaseUrl(argv[i + 1]) != B_OK) { 131 fprintf(stderr, "malformed web app base url; %s\n", argv[i + 1]); 132 Quit(); 133 } 134 else 135 fprintf(stderr, "did configure the web base url; %s\n",argv[i + 1]); 136 137 i += 2; 138 } else { 139 BEntry entry(argv[i], true); 140 _Open(entry); 141 i++; 142 } 143 } 144 } 145 146 147 // #pragma mark - private 148 149 150 void 151 App::_Open(const BEntry& entry) 152 { 153 BPath path; 154 if (!entry.Exists() || !entry.GetPath(&path) == B_OK) { 155 fprintf(stderr, "Package file not found: %s\n", path.Path()); 156 return; 157 } 158 159 // Try to parse package file via Package Kit 160 BPackageKit::BPackageInfo info; 161 status_t status = info.ReadFromPackageFile(path.Path()); 162 if (status != B_OK) { 163 fprintf(stderr, "Failed to parse package file: %s\n", 164 strerror(status)); 165 return; 166 } 167 168 // Transfer information into PackageInfo 169 PackageInfoRef package(new(std::nothrow) PackageInfo(info), true); 170 if (package.Get() == NULL) { 171 fprintf(stderr, "Could not allocate PackageInfo\n"); 172 return; 173 } 174 175 package->SetLocalFilePath(path.Path()); 176 177 BMessage settings; 178 _LoadSettings(settings); 179 180 MainWindow* window = new MainWindow(settings, package); 181 _ShowWindow(window); 182 } 183 184 185 void 186 App::_ShowWindow(MainWindow* window) 187 { 188 window->Show(); 189 fWindowCount++; 190 } 191 192 193 bool 194 App::_LoadSettings(BMessage& settings) 195 { 196 if (!fSettingsRead) { 197 fSettings = true; 198 if (load_settings(&fSettings, "main_settings", "HaikuDepot") != B_OK) 199 fSettings.MakeEmpty(); 200 } 201 settings = fSettings; 202 return !fSettings.IsEmpty(); 203 } 204 205 206 void 207 App::_StoreSettings(const BMessage& settings) 208 { 209 // Take what is in settings and replace data under the same name in 210 // fSettings, leaving anything in fSettings that is not contained in 211 // settings. 212 int32 i = 0; 213 214 char* name; 215 type_code type; 216 int32 count; 217 218 while (settings.GetInfo(B_ANY_TYPE, i++, &name, &type, &count) == B_OK) { 219 fSettings.RemoveName(name); 220 for (int32 j = 0; j < count; j++) { 221 const void* data; 222 ssize_t size; 223 if (settings.FindData(name, type, j, &data, &size) != B_OK) 224 break; 225 fSettings.AddData(name, type, data, size); 226 } 227 } 228 229 save_settings(&fSettings, "main_settings", "HaikuDepot"); 230 } 231 232 233 // #pragma mark - 234 235 236 static const char* kPackageDaemonSignature 237 = "application/x-vnd.haiku-package_daemon"; 238 239 void 240 App::_CheckPackageDaemonRuns() 241 { 242 while (!be_roster->IsRunning(kPackageDaemonSignature)) { 243 BAlert* alert = new BAlert("start_package_daemon", 244 B_TRANSLATE("HaikuDepot needs the package daemon to function, " 245 "and it appears to be not running.\n" 246 "Would you like to start it now?"), 247 B_TRANSLATE("No, quit HaikuDepot"), 248 B_TRANSLATE("Start package daemon"), NULL, B_WIDTH_AS_USUAL, 249 B_WARNING_ALERT); 250 alert->SetShortcut(0, B_ESCAPE); 251 252 if (alert->Go() == 0) 253 exit(1); 254 255 if (!_LaunchPackageDaemon()) 256 break; 257 } 258 } 259 260 261 bool 262 App::_LaunchPackageDaemon() 263 { 264 status_t ret = be_roster->Launch(kPackageDaemonSignature); 265 if (ret != B_OK) { 266 BString errorMessage 267 = B_TRANSLATE("Starting the package daemon failed:\n\n%Error%"); 268 errorMessage.ReplaceAll("%Error%", strerror(ret)); 269 270 BAlert* alert = new BAlert("package_daemon_problem", 271 errorMessage, 272 B_TRANSLATE("Quit HaikuDepot"), 273 B_TRANSLATE("Try again"), NULL, B_WIDTH_AS_USUAL, 274 B_WARNING_ALERT); 275 alert->SetShortcut(0, B_ESCAPE); 276 277 if (alert->Go() == 0) 278 return false; 279 } 280 // TODO: Would be nice to send a message to the package daemon instead 281 // and get a reply once it is ready. 282 snooze(2000000); 283 return true; 284 } 285 286