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 "NetworkCookieJar.h" 53 #include "WebKitInfo.h" 54 #include "WebPage.h" 55 #include "WebSettings.h" 56 #include "WebView.h" 57 #include "WebViewConstants.h" 58 59 60 #undef B_TRANSLATION_CONTEXT 61 #define B_TRANSLATION_CONTEXT "WebPositive" 62 63 const char* kApplicationSignature = "application/x-vnd.Haiku-WebPositive"; 64 const char* kApplicationName = B_TRANSLATE_SYSTEM_NAME("WebPositive"); 65 static const uint32 PRELOAD_BROWSING_HISTORY = 'plbh'; 66 67 #define ENABLE_NATIVE_COOKIES 1 68 69 70 BrowserApp::BrowserApp() 71 : 72 BApplication(kApplicationSignature), 73 fWindowCount(0), 74 fLastWindowFrame(50, 50, 950, 750), 75 fLaunchRefsMessage(0), 76 fInitialized(false), 77 fSettings(NULL), 78 fCookies(NULL), 79 fContext(NULL), 80 fDownloadWindow(NULL), 81 fSettingsWindow(NULL), 82 fConsoleWindow(NULL) 83 { 84 #if ENABLE_NATIVE_COOKIES 85 BString cookieStorePath = kApplicationName; 86 cookieStorePath << "/Cookies"; 87 fCookies = new SettingsMessage(B_USER_SETTINGS_DIRECTORY, 88 cookieStorePath.String()); 89 BMessage cookieArchive = fCookies->GetValue("cookies", cookieArchive); 90 fContext = new BUrlContext(); 91 fContext->SetCookieJar(BNetworkCookieJar(&cookieArchive)); 92 #endif 93 } 94 95 96 BrowserApp::~BrowserApp() 97 { 98 delete fLaunchRefsMessage; 99 delete fSettings; 100 delete fCookies; 101 delete fContext; 102 } 103 104 105 void 106 BrowserApp::AboutRequested() 107 { 108 BAboutWindow* window = new BAboutWindow(kApplicationName, 109 kApplicationSignature); 110 111 // create the about window 112 113 const char* authors[] = { 114 "Andrea Anzani", 115 "Stephan Aßmus", 116 "Alexandre Deckner", 117 "Rene Gollent", 118 "Ryan Leavengood", 119 "Michael Lotz", 120 "Maxime Simon", 121 NULL 122 }; 123 124 BString aboutText(""); 125 aboutText << "HaikuWebKit " << WebKitInfo::HaikuWebKitVersion(); 126 aboutText << "\nWebKit " << WebKitInfo::WebKitVersion(); 127 128 window->AddCopyright(2007, "Haiku, Inc."); 129 window->AddAuthors(authors); 130 window->AddExtraInfo(aboutText.String()); 131 132 window->Show(); 133 } 134 135 136 void 137 BrowserApp::ArgvReceived(int32 argc, char** argv) 138 { 139 BMessage message(B_REFS_RECEIVED); 140 for (int i = 1; i < argc; i++) { 141 if (strcmp("-f", argv[i]) == 0 142 || strcmp("--fullscreen", argv[i]) == 0) { 143 message.AddBool("fullscreen", true); 144 continue; 145 } 146 const char* url = argv[i]; 147 BEntry entry(argv[i], true); 148 BPath path; 149 if (entry.Exists() && entry.GetPath(&path) == B_OK) 150 url = path.Path(); 151 message.AddString("url", url); 152 } 153 // Upon program launch, it will buffer a copy of the message, since 154 // ArgReceived() is called before ReadyToRun(). 155 RefsReceived(&message); 156 } 157 158 159 void 160 BrowserApp::ReadyToRun() 161 { 162 // Since we will essentially run the GUI... 163 set_thread_priority(Thread(), B_DISPLAY_PRIORITY); 164 165 BWebPage::InitializeOnce(); 166 BWebPage::SetCacheModel(B_WEBKIT_CACHE_MODEL_WEB_BROWSER); 167 168 BPath path; 169 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK 170 && path.Append(kApplicationName) == B_OK 171 && create_directory(path.Path(), 0777) == B_OK) { 172 173 BWebSettings::SetPersistentStoragePath(path.Path()); 174 } 175 176 BString mainSettingsPath(kApplicationName); 177 mainSettingsPath << "/Application"; 178 fSettings = new SettingsMessage(B_USER_SETTINGS_DIRECTORY, 179 mainSettingsPath.String()); 180 181 fLastWindowFrame = fSettings->GetValue("window frame", fLastWindowFrame); 182 BRect defaultDownloadWindowFrame(-10, -10, 365, 265); 183 BRect downloadWindowFrame = fSettings->GetValue("downloads window frame", 184 defaultDownloadWindowFrame); 185 BRect settingsWindowFrame = fSettings->GetValue("settings window frame", 186 BRect()); 187 BRect consoleWindowFrame = fSettings->GetValue("console window frame", 188 BRect(50, 50, 400, 300)); 189 bool showDownloads = fSettings->GetValue("show downloads", false); 190 191 fDownloadWindow = new DownloadWindow(downloadWindowFrame, showDownloads, 192 fSettings); 193 if (downloadWindowFrame == defaultDownloadWindowFrame) { 194 // Initially put download window in lower right of screen. 195 BRect screenFrame = BScreen().Frame(); 196 BMessage decoratorSettings; 197 fDownloadWindow->GetDecoratorSettings(&decoratorSettings); 198 float borderWidth = 0; 199 if (decoratorSettings.FindFloat("border width", &borderWidth) != B_OK) 200 borderWidth = 5; 201 fDownloadWindow->MoveTo(screenFrame.Width() 202 - fDownloadWindow->Frame().Width() - borderWidth, 203 screenFrame.Height() - fDownloadWindow->Frame().Height() 204 - borderWidth); 205 } 206 fSettingsWindow = new SettingsWindow(settingsWindowFrame, fSettings); 207 208 BWebPage::SetDownloadListener(BMessenger(fDownloadWindow)); 209 210 fConsoleWindow = new ConsoleWindow(consoleWindowFrame); 211 212 fInitialized = true; 213 214 int32 pagesCreated = 0; 215 bool fullscreen = false; 216 if (fLaunchRefsMessage) { 217 _RefsReceived(fLaunchRefsMessage, &pagesCreated, &fullscreen); 218 delete fLaunchRefsMessage; 219 fLaunchRefsMessage = NULL; 220 } 221 if (pagesCreated == 0) 222 _CreateNewWindow("", fullscreen); 223 224 PostMessage(PRELOAD_BROWSING_HISTORY); 225 } 226 227 228 void 229 BrowserApp::MessageReceived(BMessage* message) 230 { 231 switch (message->what) { 232 case PRELOAD_BROWSING_HISTORY: 233 // Accessing the default instance will load the history from disk. 234 BrowsingHistory::DefaultInstance(); 235 break; 236 case B_SILENT_RELAUNCH: 237 _CreateNewPage(""); 238 break; 239 case NEW_WINDOW: { 240 BString url; 241 if (message->FindString("url", &url) != B_OK) 242 break; 243 _CreateNewWindow(url); 244 break; 245 } 246 case NEW_TAB: { 247 BrowserWindow* window; 248 if (message->FindPointer("window", 249 reinterpret_cast<void**>(&window)) != B_OK) 250 break; 251 BString url; 252 message->FindString("url", &url); 253 bool select = false; 254 message->FindBool("select", &select); 255 _CreateNewTab(window, url, select); 256 break; 257 } 258 case WINDOW_OPENED: 259 fWindowCount++; 260 fDownloadWindow->SetMinimizeOnClose(false); 261 break; 262 case WINDOW_CLOSED: 263 fWindowCount--; 264 message->FindRect("window frame", &fLastWindowFrame); 265 if (fWindowCount <= 0) 266 PostMessage(B_QUIT_REQUESTED); 267 break; 268 269 case SHOW_DOWNLOAD_WINDOW: 270 _ShowWindow(message, fDownloadWindow); 271 break; 272 case SHOW_SETTINGS_WINDOW: 273 _ShowWindow(message, fSettingsWindow); 274 break; 275 case SHOW_CONSOLE_WINDOW: 276 _ShowWindow(message, fConsoleWindow); 277 break; 278 case ADD_CONSOLE_MESSAGE: 279 fConsoleWindow->PostMessage(message); 280 break; 281 282 default: 283 BApplication::MessageReceived(message); 284 break; 285 } 286 } 287 288 289 void 290 BrowserApp::RefsReceived(BMessage* message) 291 { 292 if (!fInitialized) { 293 delete fLaunchRefsMessage; 294 fLaunchRefsMessage = new BMessage(*message); 295 return; 296 } 297 298 _RefsReceived(message); 299 } 300 301 302 bool 303 BrowserApp::QuitRequested() 304 { 305 if (fDownloadWindow->DownloadsInProgress()) { 306 BAlert* alert = new BAlert(B_TRANSLATE("Downloads in progress"), 307 B_TRANSLATE("There are still downloads in progress, do you really " 308 "want to quit WebPositive now?"), B_TRANSLATE("Quit"), 309 B_TRANSLATE("Continue downloads")); 310 int32 choice = alert->Go(); 311 if (choice == 1) { 312 if (fWindowCount == 0) { 313 if (fDownloadWindow->Lock()) { 314 fDownloadWindow->SetWorkspaces(1 << current_workspace()); 315 if (fDownloadWindow->IsHidden()) 316 fDownloadWindow->Show(); 317 else 318 fDownloadWindow->Activate(); 319 fDownloadWindow->SetMinimizeOnClose(true); 320 fDownloadWindow->Unlock(); 321 return false; 322 } 323 } else 324 return false; 325 } 326 } 327 328 for (int i = 0; BWindow* window = WindowAt(i); i++) { 329 BrowserWindow* webWindow = dynamic_cast<BrowserWindow*>(window); 330 if (!webWindow) 331 continue; 332 if (!webWindow->Lock()) 333 continue; 334 if (webWindow->QuitRequested()) { 335 fLastWindowFrame = webWindow->WindowFrame(); 336 webWindow->Quit(); 337 i--; 338 } else { 339 webWindow->Unlock(); 340 return false; 341 } 342 } 343 344 BWebPage::ShutdownOnce(); 345 346 fSettings->SetValue("window frame", fLastWindowFrame); 347 if (fDownloadWindow->Lock()) { 348 fSettings->SetValue("downloads window frame", fDownloadWindow->Frame()); 349 fSettings->SetValue("show downloads", !fDownloadWindow->IsHidden()); 350 fDownloadWindow->Unlock(); 351 } 352 if (fSettingsWindow->Lock()) { 353 fSettings->SetValue("settings window frame", fSettingsWindow->Frame()); 354 fSettingsWindow->Unlock(); 355 } 356 357 if (fConsoleWindow->Lock()) { 358 fSettings->SetValue("console window frame", fConsoleWindow->Frame()); 359 fConsoleWindow->Unlock(); 360 } 361 362 BMessage cookieArchive; 363 BNetworkCookieJar& cookieJar = fContext->GetCookieJar(); 364 if (cookieJar.Archive(&cookieArchive) == B_OK) 365 fCookies->SetValue("cookies", cookieArchive); 366 367 return true; 368 } 369 370 371 void 372 BrowserApp::_RefsReceived(BMessage* message, int32* _pagesCreated, 373 bool* _fullscreen) 374 { 375 int32 pagesCreated = 0; 376 377 BrowserWindow* window = NULL; 378 if (message->FindPointer("window", (void**)&window) != B_OK) 379 window = NULL; 380 381 bool fullscreen; 382 if (message->FindBool("fullscreen", &fullscreen) != B_OK) 383 fullscreen = false; 384 385 entry_ref ref; 386 for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { 387 BEntry entry(&ref, true); 388 if (!entry.Exists()) 389 continue; 390 BPath path; 391 if (entry.GetPath(&path) != B_OK) 392 continue; 393 BUrl url(path); 394 window = _CreateNewPage(url.UrlString(), window, fullscreen, 395 pagesCreated == 0); 396 pagesCreated++; 397 } 398 399 BString url; 400 for (int32 i = 0; message->FindString("url", i, &url) == B_OK; i++) { 401 window = _CreateNewPage(url, window, fullscreen, pagesCreated == 0); 402 pagesCreated++; 403 } 404 405 if (_pagesCreated != NULL) 406 *_pagesCreated = pagesCreated; 407 if (_fullscreen != NULL) 408 *_fullscreen = fullscreen; 409 } 410 411 412 BrowserWindow* 413 BrowserApp::_CreateNewPage(const BString& url, BrowserWindow* webWindow, 414 bool fullscreen, bool useBlankTab) 415 { 416 // Let's first see if we must target a specific window... 417 if (webWindow && webWindow->Lock()) { 418 if (useBlankTab && webWindow->IsBlankTab()) { 419 if (url.Length() != 0) 420 webWindow->CurrentWebView()->LoadURL(url); 421 } else 422 webWindow->CreateNewTab(url, true); 423 webWindow->Activate(); 424 webWindow->CurrentWebView()->MakeFocus(true); 425 webWindow->Unlock(); 426 return webWindow; 427 } 428 429 // Otherwise, try to find one in the current workspace 430 uint32 workspace = 1 << current_workspace(); 431 432 bool loadedInWindowOnCurrentWorkspace = false; 433 for (int i = 0; BWindow* window = WindowAt(i); i++) { 434 webWindow = dynamic_cast<BrowserWindow*>(window); 435 if (!webWindow) 436 continue; 437 438 if (webWindow->Lock()) { 439 if (webWindow->Workspaces() & workspace) { 440 if (useBlankTab && webWindow->IsBlankTab()) { 441 if (url.Length() != 0) 442 webWindow->CurrentWebView()->LoadURL(url); 443 } else 444 webWindow->CreateNewTab(url, true); 445 webWindow->Activate(); 446 webWindow->CurrentWebView()->MakeFocus(true); 447 loadedInWindowOnCurrentWorkspace = true; 448 } 449 webWindow->Unlock(); 450 } 451 if (loadedInWindowOnCurrentWorkspace) 452 return webWindow; 453 } 454 455 // Finally, if no window is available, let's create one. 456 return _CreateNewWindow(url, fullscreen); 457 } 458 459 460 BrowserWindow* 461 BrowserApp::_CreateNewWindow(const BString& url, bool fullscreen) 462 { 463 // Offset the window frame unless this is the first window created in the 464 // session. 465 if (fWindowCount > 0) 466 fLastWindowFrame.OffsetBy(20, 20); 467 if (!BScreen().Frame().Contains(fLastWindowFrame)) 468 fLastWindowFrame.OffsetTo(50, 50); 469 470 BrowserWindow* window = new BrowserWindow(fLastWindowFrame, fSettings, 471 url, fContext); 472 if (fullscreen) 473 window->ToggleFullscreen(); 474 window->Show(); 475 return window; 476 } 477 478 479 void 480 BrowserApp::_CreateNewTab(BrowserWindow* window, const BString& url, 481 bool select) 482 { 483 if (!window->Lock()) 484 return; 485 window->CreateNewTab(url, select); 486 window->Unlock(); 487 } 488 489 490 void 491 BrowserApp::_ShowWindow(const BMessage* message, BWindow* window) 492 { 493 BAutolock _(window); 494 uint32 workspaces; 495 if (message->FindUInt32("workspaces", &workspaces) == B_OK) 496 window->SetWorkspaces(workspaces); 497 if (window->IsHidden()) 498 window->Show(); 499 else 500 window->Activate(); 501 } 502 503 504 // #pragma mark - 505 506 507 int 508 main(int, char**) 509 { 510 try { 511 new BrowserApp(); 512 be_app->Run(); 513 delete be_app; 514 } catch (...) { 515 debugger("Exception caught."); 516 } 517 518 return 0; 519 } 520 521