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 <debugger.h> 42 43 #include <stdio.h> 44 45 #include "BrowserWindow.h" 46 #include "BrowsingHistory.h" 47 #include "DownloadWindow.h" 48 #include "SettingsMessage.h" 49 #include "SettingsWindow.h" 50 #include "svn_revision.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 0 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 fCookieJar(NULL), 78 fDownloadWindow(NULL), 79 fSettingsWindow(NULL), 80 fAboutWindow(NULL) 81 { 82 } 83 84 85 BrowserApp::~BrowserApp() 86 { 87 delete fLaunchRefsMessage; 88 delete fSettings; 89 delete fCookies; 90 delete fCookieJar; 91 92 if (fAboutWindow != NULL && fAboutWindow->Lock()) 93 fAboutWindow->Quit(); 94 } 95 96 97 void 98 BrowserApp::AboutRequested() 99 { 100 if (fAboutWindow == NULL) { 101 // create the about window 102 103 const char* authors[] = { 104 "Andrea Anzani", 105 "Stephan Aßmus", 106 "Alexandre Deckner", 107 "Rene Gollent", 108 "Ryan Leavengood", 109 "Michael Lotz", 110 "Maxime Simon", 111 NULL 112 }; 113 114 BString aboutText(""); 115 aboutText << "HaikuWebKit " << WebKitInfo::HaikuWebKitVersion(); 116 aboutText << " (" << WebKitInfo::HaikuWebKitRevision() << ")"; 117 aboutText << "\nWebKit " << WebKitInfo::WebKitVersion(); 118 aboutText << " (" << WebKitInfo::WebKitRevision() << ")"; 119 120 fAboutWindow = new BAboutWindow(kApplicationName, 121 kApplicationSignature); 122 fAboutWindow->AddCopyright(2007, "Haiku, Inc."); 123 fAboutWindow->AddAuthors(authors); 124 fAboutWindow->AddExtraInfo(aboutText.String()); 125 fAboutWindow->Show(); 126 } else if (fAboutWindow->IsHidden()) 127 fAboutWindow->Show(); 128 else 129 fAboutWindow->Activate(); 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 #if ENABLE_NATIVE_COOKIES 178 mainSettingsPath = kApplicationName; 179 mainSettingsPath << "/Cookies"; 180 fCookies = new SettingsMessage(B_USER_SETTINGS_DIRECTORY, 181 mainSettingsPath.String()); 182 BMessage cookieArchive; 183 cookieArchive = fCookies->GetValue("cookies", cookieArchive); 184 fCookieJar = new BNetworkCookieJar(cookieArchive); 185 BWebPage::SetCookieJar(fCookieJar); 186 #endif 187 188 fLastWindowFrame = fSettings->GetValue("window frame", fLastWindowFrame); 189 BRect defaultDownloadWindowFrame(-10, -10, 365, 265); 190 BRect downloadWindowFrame = fSettings->GetValue("downloads window frame", 191 defaultDownloadWindowFrame); 192 BRect settingsWindowFrame = fSettings->GetValue("settings window frame", 193 BRect()); 194 bool showDownloads = fSettings->GetValue("show downloads", false); 195 196 fDownloadWindow = new DownloadWindow(downloadWindowFrame, showDownloads, 197 fSettings); 198 if (downloadWindowFrame == defaultDownloadWindowFrame) { 199 // Initially put download window in lower right of screen. 200 BRect screenFrame = BScreen().Frame(); 201 BMessage decoratorSettings; 202 fDownloadWindow->GetDecoratorSettings(&decoratorSettings); 203 float borderWidth = 0; 204 if (decoratorSettings.FindFloat("border width", &borderWidth) != B_OK) 205 borderWidth = 5; 206 fDownloadWindow->MoveTo(screenFrame.Width() 207 - fDownloadWindow->Frame().Width() - borderWidth, 208 screenFrame.Height() - fDownloadWindow->Frame().Height() 209 - borderWidth); 210 } 211 fSettingsWindow = new SettingsWindow(settingsWindowFrame, fSettings); 212 213 BWebPage::SetDownloadListener(BMessenger(fDownloadWindow)); 214 215 fInitialized = true; 216 217 int32 pagesCreated = 0; 218 bool fullscreen = false; 219 if (fLaunchRefsMessage) { 220 _RefsReceived(fLaunchRefsMessage, &pagesCreated, &fullscreen); 221 delete fLaunchRefsMessage; 222 fLaunchRefsMessage = NULL; 223 } 224 if (pagesCreated == 0) 225 _CreateNewWindow("", fullscreen); 226 227 PostMessage(PRELOAD_BROWSING_HISTORY); 228 } 229 230 231 void 232 BrowserApp::MessageReceived(BMessage* message) 233 { 234 switch (message->what) { 235 case PRELOAD_BROWSING_HISTORY: 236 // Accessing the default instance will load the history from disk. 237 BrowsingHistory::DefaultInstance(); 238 break; 239 case B_SILENT_RELAUNCH: 240 _CreateNewPage(""); 241 break; 242 case NEW_WINDOW: { 243 BString url; 244 if (message->FindString("url", &url) != B_OK) 245 break; 246 _CreateNewWindow(url); 247 break; 248 } 249 case NEW_TAB: { 250 BrowserWindow* window; 251 if (message->FindPointer("window", 252 reinterpret_cast<void**>(&window)) != B_OK) 253 break; 254 BString url; 255 message->FindString("url", &url); 256 bool select = false; 257 message->FindBool("select", &select); 258 _CreateNewTab(window, url, select); 259 break; 260 } 261 case WINDOW_OPENED: 262 fWindowCount++; 263 fDownloadWindow->SetMinimizeOnClose(false); 264 break; 265 case WINDOW_CLOSED: 266 fWindowCount--; 267 message->FindRect("window frame", &fLastWindowFrame); 268 if (fWindowCount <= 0) 269 PostMessage(B_QUIT_REQUESTED); 270 break; 271 272 case SHOW_DOWNLOAD_WINDOW: 273 _ShowWindow(message, fDownloadWindow); 274 break; 275 case SHOW_SETTINGS_WINDOW: 276 _ShowWindow(message, fSettingsWindow); 277 break; 278 279 default: 280 BApplication::MessageReceived(message); 281 break; 282 } 283 } 284 285 286 void 287 BrowserApp::RefsReceived(BMessage* message) 288 { 289 if (!fInitialized) { 290 delete fLaunchRefsMessage; 291 fLaunchRefsMessage = new BMessage(*message); 292 return; 293 } 294 295 _RefsReceived(message); 296 } 297 298 299 bool 300 BrowserApp::QuitRequested() 301 { 302 if (fDownloadWindow->DownloadsInProgress()) { 303 BAlert* alert = new BAlert(B_TRANSLATE("Downloads in progress"), 304 B_TRANSLATE("There are still downloads in progress, do you really " 305 "want to quit WebPositive now?"), B_TRANSLATE("Quit"), 306 B_TRANSLATE("Continue downloads")); 307 int32 choice = alert->Go(); 308 if (choice == 1) { 309 if (fWindowCount == 0) { 310 if (fDownloadWindow->Lock()) { 311 fDownloadWindow->SetWorkspaces(1 << current_workspace()); 312 if (fDownloadWindow->IsHidden()) 313 fDownloadWindow->Show(); 314 else 315 fDownloadWindow->Activate(); 316 fDownloadWindow->SetMinimizeOnClose(true); 317 fDownloadWindow->Unlock(); 318 return false; 319 } 320 } else 321 return false; 322 } 323 } 324 325 for (int i = 0; BWindow* window = WindowAt(i); i++) { 326 BrowserWindow* webWindow = dynamic_cast<BrowserWindow*>(window); 327 if (!webWindow) 328 continue; 329 if (!webWindow->Lock()) 330 continue; 331 if (webWindow->QuitRequested()) { 332 fLastWindowFrame = webWindow->WindowFrame(); 333 webWindow->Quit(); 334 i--; 335 } else { 336 webWindow->Unlock(); 337 return false; 338 } 339 } 340 341 BWebPage::ShutdownOnce(); 342 343 fSettings->SetValue("window frame", fLastWindowFrame); 344 if (fDownloadWindow->Lock()) { 345 fSettings->SetValue("downloads window frame", fDownloadWindow->Frame()); 346 fSettings->SetValue("show downloads", !fDownloadWindow->IsHidden()); 347 fDownloadWindow->Unlock(); 348 } 349 if (fSettingsWindow->Lock()) { 350 fSettings->SetValue("settings window frame", fSettingsWindow->Frame()); 351 fSettingsWindow->Unlock(); 352 } 353 354 BMessage cookieArchive; 355 if (fCookieJar != NULL && fCookieJar->Archive(&cookieArchive) == B_OK) 356 fCookies->SetValue("cookies", cookieArchive); 357 358 return true; 359 } 360 361 362 void 363 BrowserApp::_RefsReceived(BMessage* message, int32* _pagesCreated, 364 bool* _fullscreen) 365 { 366 int32 pagesCreated = 0; 367 368 bool fullscreen; 369 if (message->FindBool("fullscreen", &fullscreen) != B_OK) 370 fullscreen = false; 371 372 entry_ref ref; 373 for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { 374 BEntry entry(&ref, true); 375 if (!entry.Exists()) 376 continue; 377 BPath path; 378 if (entry.GetPath(&path) != B_OK) 379 continue; 380 BString url; 381 url << path.Path(); 382 _CreateNewPage(url, fullscreen); 383 pagesCreated++; 384 } 385 386 BString url; 387 for (int32 i = 0; message->FindString("url", i, &url) == B_OK; i++) { 388 _CreateNewPage(url, fullscreen); 389 pagesCreated++; 390 } 391 392 if (_pagesCreated != NULL) 393 *_pagesCreated = pagesCreated; 394 if (_fullscreen != NULL) 395 *_fullscreen = fullscreen; 396 } 397 398 399 void 400 BrowserApp::_CreateNewPage(const BString& url, bool fullscreen) 401 { 402 uint32 workspace = 1 << current_workspace(); 403 404 bool loadedInWindowOnCurrentWorkspace = false; 405 for (int i = 0; BWindow* window = WindowAt(i); i++) { 406 BrowserWindow* webWindow = dynamic_cast<BrowserWindow*>(window); 407 if (!webWindow) 408 continue; 409 if (webWindow->Lock()) { 410 if (webWindow->Workspaces() & workspace) { 411 if (webWindow->IsBlankTab()) { 412 if (url.Length() != 0) 413 webWindow->CurrentWebView()->LoadURL(url); 414 } else 415 webWindow->CreateNewTab(url, true); 416 webWindow->Activate(); 417 webWindow->CurrentWebView()->MakeFocus(true); 418 loadedInWindowOnCurrentWorkspace = true; 419 } 420 webWindow->Unlock(); 421 } 422 if (loadedInWindowOnCurrentWorkspace) 423 return; 424 } 425 _CreateNewWindow(url, fullscreen); 426 } 427 428 429 void 430 BrowserApp::_CreateNewWindow(const BString& url, bool fullscreen) 431 { 432 // Offset the window frame unless this is the first window created in the 433 // session. 434 if (fWindowCount > 0) 435 fLastWindowFrame.OffsetBy(20, 20); 436 if (!BScreen().Frame().Contains(fLastWindowFrame)) 437 fLastWindowFrame.OffsetTo(50, 50); 438 439 BrowserWindow* window = new BrowserWindow(fLastWindowFrame, fSettings, 440 url); 441 if (fullscreen) 442 window->ToggleFullscreen(); 443 window->Show(); 444 } 445 446 447 void 448 BrowserApp::_CreateNewTab(BrowserWindow* window, const BString& url, 449 bool select) 450 { 451 if (!window->Lock()) 452 return; 453 window->CreateNewTab(url, select); 454 window->Unlock(); 455 } 456 457 458 void 459 BrowserApp::_ShowWindow(const BMessage* message, BWindow* window) 460 { 461 BAutolock _(window); 462 uint32 workspaces; 463 if (message->FindUInt32("workspaces", &workspaces) == B_OK) 464 window->SetWorkspaces(workspaces); 465 if (window->IsHidden()) 466 window->Show(); 467 else 468 window->Activate(); 469 } 470 471 472 // #pragma mark - 473 474 475 int 476 main(int, char**) 477 { 478 try { 479 new BrowserApp(); 480 be_app->Run(); 481 delete be_app; 482 } catch (...) { 483 debugger("Exception caught."); 484 } 485 486 return 0; 487 } 488 489