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