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