1 /* 2 * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> 3 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de> 4 * 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "BrowserApp.h" 30 31 #include <AboutWindow.h> 32 #include <Alert.h> 33 #include <Autolock.h> 34 #include <Catalog.h> 35 #include <Directory.h> 36 #include <Entry.h> 37 #include <FindDirectory.h> 38 #include <Locale.h> 39 #include <Path.h> 40 #include <Screen.h> 41 #include <UrlContext.h> 42 #include <debugger.h> 43 44 #include <stdio.h> 45 46 #include "BrowserWindow.h" 47 #include "BrowsingHistory.h" 48 #include "DownloadWindow.h" 49 #include "SettingsMessage.h" 50 #include "SettingsWindow.h" 51 #include "ConsoleWindow.h" 52 #include "CookieWindow.h" 53 #include "NetworkCookieJar.h" 54 #include "WebKitInfo.h" 55 #include "WebPage.h" 56 #include "WebSettings.h" 57 #include "WebView.h" 58 #include "WebViewConstants.h" 59 60 61 #undef B_TRANSLATION_CONTEXT 62 #define B_TRANSLATION_CONTEXT "WebPositive" 63 64 const char* kApplicationSignature = "application/x-vnd.Haiku-WebPositive"; 65 const char* kApplicationName = B_TRANSLATE_SYSTEM_NAME("WebPositive"); 66 static const uint32 PRELOAD_BROWSING_HISTORY = 'plbh'; 67 68 #define ENABLE_NATIVE_COOKIES 1 69 70 71 BrowserApp::BrowserApp() 72 : 73 BApplication(kApplicationSignature), 74 fWindowCount(0), 75 fLastWindowFrame(50, 50, 950, 750), 76 fLaunchRefsMessage(0), 77 fInitialized(false), 78 fSettings(NULL), 79 fCookies(NULL), 80 fSession(NULL), 81 fContext(NULL), 82 fDownloadWindow(NULL), 83 fSettingsWindow(NULL), 84 fConsoleWindow(NULL), 85 fCookieWindow(NULL) 86 { 87 #if ENABLE_NATIVE_COOKIES 88 BString cookieStorePath = kApplicationName; 89 cookieStorePath << "/Cookies"; 90 fCookies = new SettingsMessage(B_USER_SETTINGS_DIRECTORY, 91 cookieStorePath.String()); 92 fContext = new BUrlContext(); 93 if (fCookies->InitCheck() == B_OK) { 94 BMessage cookieArchive = fCookies->GetValue("cookies", cookieArchive); 95 fContext->SetCookieJar(BNetworkCookieJar(&cookieArchive)); 96 } 97 #endif 98 99 BString sessionStorePath = kApplicationName; 100 sessionStorePath << "/Session"; 101 fSession = new SettingsMessage(B_USER_SETTINGS_DIRECTORY, 102 sessionStorePath.String()); 103 } 104 105 106 BrowserApp::~BrowserApp() 107 { 108 delete fLaunchRefsMessage; 109 delete fSettings; 110 delete fCookies; 111 delete fSession; 112 delete fContext; 113 } 114 115 116 void 117 BrowserApp::AboutRequested() 118 { 119 BAboutWindow* window = new BAboutWindow(kApplicationName, 120 kApplicationSignature); 121 122 // create the about window 123 124 const char* authors[] = { 125 "Andrea Anzani", 126 "Stephan Aßmus", 127 "Alexandre Deckner", 128 "Rene Gollent", 129 "Ryan Leavengood", 130 "Michael Lotz", 131 "Maxime Simon", 132 NULL 133 }; 134 135 BString aboutText(""); 136 aboutText << "HaikuWebKit " << WebKitInfo::HaikuWebKitVersion(); 137 aboutText << "\nWebKit " << WebKitInfo::WebKitVersion(); 138 139 window->AddCopyright(2007, "Haiku, Inc."); 140 window->AddAuthors(authors); 141 window->AddExtraInfo(aboutText.String()); 142 143 window->Show(); 144 } 145 146 147 void 148 BrowserApp::ArgvReceived(int32 argc, char** argv) 149 { 150 BMessage message(B_REFS_RECEIVED); 151 for (int i = 1; i < argc; i++) { 152 if (strcmp("-f", argv[i]) == 0 153 || strcmp("--fullscreen", argv[i]) == 0) { 154 message.AddBool("fullscreen", true); 155 continue; 156 } 157 const char* url = argv[i]; 158 BEntry entry(argv[i], true); 159 BPath path; 160 if (entry.Exists() && entry.GetPath(&path) == B_OK) 161 url = path.Path(); 162 message.AddString("url", url); 163 } 164 // Upon program launch, it will buffer a copy of the message, since 165 // ArgReceived() is called before ReadyToRun(). 166 RefsReceived(&message); 167 } 168 169 170 void 171 BrowserApp::ReadyToRun() 172 { 173 // Since we will essentially run the GUI... 174 set_thread_priority(Thread(), B_DISPLAY_PRIORITY); 175 176 BWebPage::InitializeOnce(); 177 BWebPage::SetCacheModel(B_WEBKIT_CACHE_MODEL_WEB_BROWSER); 178 179 BPath path; 180 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK 181 && path.Append(kApplicationName) == B_OK 182 && create_directory(path.Path(), 0777) == B_OK) { 183 184 BWebSettings::SetPersistentStoragePath(path.Path()); 185 } 186 187 BString mainSettingsPath(kApplicationName); 188 mainSettingsPath << "/Application"; 189 fSettings = new SettingsMessage(B_USER_SETTINGS_DIRECTORY, 190 mainSettingsPath.String()); 191 192 fLastWindowFrame = fSettings->GetValue("window frame", fLastWindowFrame); 193 BRect defaultDownloadWindowFrame(-10, -10, 365, 265); 194 BRect downloadWindowFrame = fSettings->GetValue("downloads window frame", 195 defaultDownloadWindowFrame); 196 BRect settingsWindowFrame = fSettings->GetValue("settings window frame", 197 BRect()); 198 BRect consoleWindowFrame = fSettings->GetValue("console window frame", 199 BRect(50, 50, 400, 300)); 200 BRect cookieWindowFrame = fSettings->GetValue("cookie window frame", 201 BRect(50, 50, 400, 300)); 202 bool showDownloads = fSettings->GetValue("show downloads", false); 203 204 fDownloadWindow = new DownloadWindow(downloadWindowFrame, showDownloads, 205 fSettings); 206 if (downloadWindowFrame == defaultDownloadWindowFrame) { 207 // Initially put download window in lower right of screen. 208 BRect screenFrame = BScreen().Frame(); 209 BMessage decoratorSettings; 210 fDownloadWindow->GetDecoratorSettings(&decoratorSettings); 211 float borderWidth = 0; 212 if (decoratorSettings.FindFloat("border width", &borderWidth) != B_OK) 213 borderWidth = 5; 214 fDownloadWindow->MoveTo(screenFrame.Width() 215 - fDownloadWindow->Frame().Width() - borderWidth, 216 screenFrame.Height() - fDownloadWindow->Frame().Height() 217 - borderWidth); 218 } 219 fSettingsWindow = new SettingsWindow(settingsWindowFrame, fSettings); 220 221 BWebPage::SetDownloadListener(BMessenger(fDownloadWindow)); 222 223 fConsoleWindow = new ConsoleWindow(consoleWindowFrame); 224 fCookieWindow = new CookieWindow(cookieWindowFrame, fContext->GetCookieJar()); 225 226 fInitialized = true; 227 228 int32 pagesCreated = 0; 229 bool fullscreen = false; 230 if (fLaunchRefsMessage) { 231 _RefsReceived(fLaunchRefsMessage, &pagesCreated, &fullscreen); 232 delete fLaunchRefsMessage; 233 fLaunchRefsMessage = NULL; 234 } 235 236 // If no refs led to a new open page, restore previous session. 237 if (fSession->InitCheck() == B_OK && pagesCreated == 0) { 238 BMessage archivedWindow; 239 for (int i = 0; fSession->FindMessage("window", i, &archivedWindow) == B_OK; 240 i++) { 241 BRect frame = archivedWindow.FindRect("window frame"); 242 BString url; 243 archivedWindow.FindString("tab", 0, &url); 244 BrowserWindow* window = new(std::nothrow) BrowserWindow(frame, 245 fSettings, url, fContext); 246 247 if (window != NULL) { 248 window->Show(); 249 pagesCreated++; 250 251 for (int j = 1; archivedWindow.FindString("tab", j, &url) == B_OK; 252 j++) { 253 printf("Create %d:%d\n", i, j); 254 _CreateNewTab(window, url, false); 255 pagesCreated++; 256 } 257 } 258 } 259 } 260 261 // If previous session did not contain any window, create a new empty one. 262 if (pagesCreated == 0) 263 _CreateNewWindow("", fullscreen); 264 265 PostMessage(PRELOAD_BROWSING_HISTORY); 266 } 267 268 269 void 270 BrowserApp::MessageReceived(BMessage* message) 271 { 272 switch (message->what) { 273 case PRELOAD_BROWSING_HISTORY: 274 // Accessing the default instance will load the history from disk. 275 BrowsingHistory::DefaultInstance(); 276 break; 277 case B_SILENT_RELAUNCH: 278 _CreateNewPage(""); 279 break; 280 case NEW_WINDOW: { 281 BString url; 282 if (message->FindString("url", &url) != B_OK) 283 break; 284 _CreateNewWindow(url); 285 break; 286 } 287 case NEW_TAB: { 288 BrowserWindow* window; 289 if (message->FindPointer("window", 290 reinterpret_cast<void**>(&window)) != B_OK) 291 break; 292 BString url; 293 message->FindString("url", &url); 294 bool select = false; 295 message->FindBool("select", &select); 296 _CreateNewTab(window, url, select); 297 break; 298 } 299 case WINDOW_OPENED: 300 fWindowCount++; 301 fDownloadWindow->SetMinimizeOnClose(false); 302 break; 303 case WINDOW_CLOSED: 304 fWindowCount--; 305 message->FindRect("window frame", &fLastWindowFrame); 306 if (fWindowCount <= 0) { 307 BMessage* message = new BMessage(B_QUIT_REQUESTED); 308 message->AddMessage("window", DetachCurrentMessage()); 309 PostMessage(message); 310 } 311 break; 312 313 case SHOW_DOWNLOAD_WINDOW: 314 _ShowWindow(message, fDownloadWindow); 315 break; 316 case SHOW_SETTINGS_WINDOW: 317 _ShowWindow(message, fSettingsWindow); 318 break; 319 case SHOW_CONSOLE_WINDOW: 320 _ShowWindow(message, fConsoleWindow); 321 break; 322 case SHOW_COOKIE_WINDOW: 323 _ShowWindow(message, fCookieWindow); 324 break; 325 case ADD_CONSOLE_MESSAGE: 326 fConsoleWindow->PostMessage(message); 327 break; 328 329 default: 330 BApplication::MessageReceived(message); 331 break; 332 } 333 } 334 335 336 void 337 BrowserApp::RefsReceived(BMessage* message) 338 { 339 if (!fInitialized) { 340 delete fLaunchRefsMessage; 341 fLaunchRefsMessage = new BMessage(*message); 342 return; 343 } 344 345 _RefsReceived(message); 346 } 347 348 349 bool 350 BrowserApp::QuitRequested() 351 { 352 if (fDownloadWindow->DownloadsInProgress()) { 353 BAlert* alert = new BAlert(B_TRANSLATE("Downloads in progress"), 354 B_TRANSLATE("There are still downloads in progress, do you really " 355 "want to quit WebPositive now?"), B_TRANSLATE("Quit"), 356 B_TRANSLATE("Continue downloads")); 357 int32 choice = alert->Go(); 358 if (choice == 1) { 359 if (fWindowCount == 0) { 360 if (fDownloadWindow->Lock()) { 361 fDownloadWindow->SetWorkspaces(1 << current_workspace()); 362 if (fDownloadWindow->IsHidden()) 363 fDownloadWindow->Show(); 364 else 365 fDownloadWindow->Activate(); 366 fDownloadWindow->SetMinimizeOnClose(true); 367 fDownloadWindow->Unlock(); 368 return false; 369 } 370 } else 371 return false; 372 } 373 } 374 375 fSession->MakeEmpty(); 376 377 /* See if we got here because the last window is already closed. 378 * In that case we only need to save that one, which is already archived */ 379 BMessage* message = CurrentMessage(); 380 BMessage windowMessage; 381 382 status_t ret = message->FindMessage("window", &windowMessage); 383 if (ret == B_OK) { 384 fSession->AddMessage("window", &windowMessage); 385 } else { 386 for (int i = 0; BWindow* window = WindowAt(i); i++) { 387 BrowserWindow* webWindow = dynamic_cast<BrowserWindow*>(window); 388 if (!webWindow) 389 continue; 390 if (!webWindow->Lock()) 391 continue; 392 393 BMessage windowArchive; 394 webWindow->Archive(&windowArchive, true); 395 fSession->AddMessage("window", &windowArchive); 396 397 if (webWindow->QuitRequested()) { 398 fLastWindowFrame = webWindow->WindowFrame(); 399 webWindow->Quit(); 400 i--; 401 } else { 402 webWindow->Unlock(); 403 return false; 404 } 405 } 406 } 407 408 BWebPage::ShutdownOnce(); 409 410 fSettings->SetValue("window frame", fLastWindowFrame); 411 if (fDownloadWindow->Lock()) { 412 fSettings->SetValue("downloads window frame", fDownloadWindow->Frame()); 413 fSettings->SetValue("show downloads", !fDownloadWindow->IsHidden()); 414 fDownloadWindow->Unlock(); 415 } 416 if (fSettingsWindow->Lock()) { 417 fSettings->SetValue("settings window frame", fSettingsWindow->Frame()); 418 fSettingsWindow->Unlock(); 419 } 420 if (fConsoleWindow->Lock()) { 421 fSettings->SetValue("console window frame", fConsoleWindow->Frame()); 422 fConsoleWindow->Unlock(); 423 } 424 if (fCookieWindow->Lock()) { 425 fSettings->SetValue("cookie window frame", fCookieWindow->Frame()); 426 fCookieWindow->Unlock(); 427 } 428 429 BMessage cookieArchive; 430 BNetworkCookieJar& cookieJar = fContext->GetCookieJar(); 431 cookieJar.PurgeForExit(); 432 if (cookieJar.Archive(&cookieArchive) == B_OK) 433 fCookies->SetValue("cookies", cookieArchive); 434 435 return true; 436 } 437 438 439 void 440 BrowserApp::_RefsReceived(BMessage* message, int32* _pagesCreated, 441 bool* _fullscreen) 442 { 443 int32 pagesCreated = 0; 444 445 BrowserWindow* window = NULL; 446 if (message->FindPointer("window", (void**)&window) != B_OK) 447 window = NULL; 448 449 bool fullscreen; 450 if (message->FindBool("fullscreen", &fullscreen) != B_OK) 451 fullscreen = false; 452 453 entry_ref ref; 454 for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { 455 BEntry entry(&ref, true); 456 if (!entry.Exists()) 457 continue; 458 BPath path; 459 if (entry.GetPath(&path) != B_OK) 460 continue; 461 BUrl url(path); 462 window = _CreateNewPage(url.UrlString(), window, fullscreen, 463 pagesCreated == 0); 464 pagesCreated++; 465 } 466 467 BString url; 468 for (int32 i = 0; message->FindString("url", i, &url) == B_OK; i++) { 469 window = _CreateNewPage(url, window, fullscreen, pagesCreated == 0); 470 pagesCreated++; 471 } 472 473 if (_pagesCreated != NULL) 474 *_pagesCreated = pagesCreated; 475 if (_fullscreen != NULL) 476 *_fullscreen = fullscreen; 477 } 478 479 480 BrowserWindow* 481 BrowserApp::_CreateNewPage(const BString& url, BrowserWindow* webWindow, 482 bool fullscreen, bool useBlankTab) 483 { 484 // Let's first see if we must target a specific window... 485 if (webWindow && webWindow->Lock()) { 486 if (useBlankTab && webWindow->IsBlankTab()) { 487 if (url.Length() != 0) 488 webWindow->CurrentWebView()->LoadURL(url); 489 } else 490 webWindow->CreateNewTab(url, true); 491 webWindow->Activate(); 492 webWindow->CurrentWebView()->MakeFocus(true); 493 webWindow->Unlock(); 494 return webWindow; 495 } 496 497 // Otherwise, try to find one in the current workspace 498 uint32 workspace = 1 << current_workspace(); 499 500 bool loadedInWindowOnCurrentWorkspace = false; 501 for (int i = 0; BWindow* window = WindowAt(i); i++) { 502 webWindow = dynamic_cast<BrowserWindow*>(window); 503 if (!webWindow) 504 continue; 505 506 if (webWindow->Lock()) { 507 if (webWindow->Workspaces() & workspace) { 508 if (useBlankTab && webWindow->IsBlankTab()) { 509 if (url.Length() != 0) 510 webWindow->CurrentWebView()->LoadURL(url); 511 } else 512 webWindow->CreateNewTab(url, true); 513 webWindow->Activate(); 514 webWindow->CurrentWebView()->MakeFocus(true); 515 loadedInWindowOnCurrentWorkspace = true; 516 } 517 webWindow->Unlock(); 518 } 519 if (loadedInWindowOnCurrentWorkspace) 520 return webWindow; 521 } 522 523 // Finally, if no window is available, let's create one. 524 return _CreateNewWindow(url, fullscreen); 525 } 526 527 528 BrowserWindow* 529 BrowserApp::_CreateNewWindow(const BString& url, bool fullscreen) 530 { 531 // Offset the window frame unless this is the first window created in the 532 // session. 533 if (fWindowCount > 0) 534 fLastWindowFrame.OffsetBy(20, 20); 535 if (!BScreen().Frame().Contains(fLastWindowFrame)) 536 fLastWindowFrame.OffsetTo(50, 50); 537 538 BrowserWindow* window = new BrowserWindow(fLastWindowFrame, fSettings, 539 url, fContext); 540 if (fullscreen) 541 window->ToggleFullscreen(); 542 window->Show(); 543 return window; 544 } 545 546 547 void 548 BrowserApp::_CreateNewTab(BrowserWindow* window, const BString& url, 549 bool select) 550 { 551 if (!window->Lock()) 552 return; 553 window->CreateNewTab(url, select); 554 window->Unlock(); 555 } 556 557 558 void 559 BrowserApp::_ShowWindow(const BMessage* message, BWindow* window) 560 { 561 BAutolock _(window); 562 uint32 workspaces; 563 if (message->FindUInt32("workspaces", &workspaces) == B_OK) 564 window->SetWorkspaces(workspaces); 565 if (window->IsHidden()) 566 window->Show(); 567 else 568 window->Activate(); 569 } 570 571 572 // #pragma mark - 573 574 575 int 576 main(int, char**) 577 { 578 try { 579 new BrowserApp(); 580 be_app->Run(); 581 delete be_app; 582 } catch (...) { 583 debugger("Exception caught."); 584 } 585 586 return 0; 587 } 588 589