2 * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
3 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
29 #include "BrowserApp.h"
31 #include <AboutWindow.h>
35 #include <Directory.h>
37 #include <FindDirectory.h>
41 #include <UrlContext.h>
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"
56 #include "WebSettings.h"
58 #include "WebViewConstants.h"
61 #undef B_TRANSLATION_CONTEXT
62 #define B_TRANSLATION_CONTEXT "WebPositive"
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';
68 #define ENABLE_NATIVE_COOKIES 1
71 BrowserApp::BrowserApp()
73 BApplication(kApplicationSignature
),
75 fLastWindowFrame(50, 50, 950, 750),
76 fLaunchRefsMessage(0),
82 fDownloadWindow(NULL
),
83 fSettingsWindow(NULL
),
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
));
99 BString sessionStorePath
= kApplicationName
;
100 sessionStorePath
<< "/Session";
101 fSession
= new SettingsMessage(B_USER_SETTINGS_DIRECTORY
,
102 sessionStorePath
.String());
106 BrowserApp::~BrowserApp()
108 delete fLaunchRefsMessage
;
117 BrowserApp::AboutRequested()
119 BAboutWindow
* window
= new BAboutWindow(kApplicationName
,
120 kApplicationSignature
);
122 // create the about window
124 const char* authors
[] = {
135 BString
aboutText("");
136 aboutText
<< "HaikuWebKit " << WebKitInfo::HaikuWebKitVersion();
137 aboutText
<< "\nWebKit " << WebKitInfo::WebKitVersion();
139 window
->AddCopyright(2007, "Haiku, Inc.");
140 window
->AddAuthors(authors
);
141 window
->AddExtraInfo(aboutText
.String());
148 BrowserApp::ArgvReceived(int32 argc
, char** argv
)
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);
157 const char* url
= argv
[i
];
158 BEntry
entry(argv
[i
], true);
160 if (entry
.Exists() && entry
.GetPath(&path
) == B_OK
)
162 message
.AddString("url", url
);
164 // Upon program launch, it will buffer a copy of the message, since
165 // ArgReceived() is called before ReadyToRun().
166 RefsReceived(&message
);
171 BrowserApp::ReadyToRun()
173 // Since we will essentially run the GUI...
174 set_thread_priority(Thread(), B_DISPLAY_PRIORITY
);
176 BWebPage::InitializeOnce();
177 BWebPage::SetCacheModel(B_WEBKIT_CACHE_MODEL_WEB_BROWSER
);
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
) {
184 BWebSettings::SetPersistentStoragePath(path
.Path());
187 BString
mainSettingsPath(kApplicationName
);
188 mainSettingsPath
<< "/Application";
189 fSettings
= new SettingsMessage(B_USER_SETTINGS_DIRECTORY
,
190 mainSettingsPath
.String());
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",
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);
204 fDownloadWindow
= new DownloadWindow(downloadWindowFrame
, showDownloads
,
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
)
214 fDownloadWindow
->MoveTo(screenFrame
.Width()
215 - fDownloadWindow
->Frame().Width() - borderWidth
,
216 screenFrame
.Height() - fDownloadWindow
->Frame().Height()
219 fSettingsWindow
= new SettingsWindow(settingsWindowFrame
, fSettings
);
221 BWebPage::SetDownloadListener(BMessenger(fDownloadWindow
));
223 fConsoleWindow
= new ConsoleWindow(consoleWindowFrame
);
224 fCookieWindow
= new CookieWindow(cookieWindowFrame
, fContext
->GetCookieJar());
228 int32 pagesCreated
= 0;
229 bool fullscreen
= false;
230 if (fLaunchRefsMessage
) {
231 _RefsReceived(fLaunchRefsMessage
, &pagesCreated
, &fullscreen
);
232 delete fLaunchRefsMessage
;
233 fLaunchRefsMessage
= NULL
;
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
;
241 BRect frame
= archivedWindow
.FindRect("window frame");
243 archivedWindow
.FindString("tab", 0, &url
);
244 BrowserWindow
* window
= new(std::nothrow
) BrowserWindow(frame
,
245 fSettings
, url
, fContext
);
247 if (window
!= NULL
) {
251 for (int j
= 1; archivedWindow
.FindString("tab", j
, &url
) == B_OK
;
253 printf("Create %d:%d\n", i
, j
);
254 _CreateNewTab(window
, url
, false);
261 // If previous session did not contain any window, create a new empty one.
262 if (pagesCreated
== 0)
263 _CreateNewWindow("", fullscreen
);
265 PostMessage(PRELOAD_BROWSING_HISTORY
);
270 BrowserApp::MessageReceived(BMessage
* message
)
272 switch (message
->what
) {
273 case PRELOAD_BROWSING_HISTORY
:
274 // Accessing the default instance will load the history from disk.
275 BrowsingHistory::DefaultInstance();
277 case B_SILENT_RELAUNCH
:
282 if (message
->FindString("url", &url
) != B_OK
)
284 _CreateNewWindow(url
);
288 BrowserWindow
* window
;
289 if (message
->FindPointer("window",
290 reinterpret_cast<void**>(&window
)) != B_OK
)
293 message
->FindString("url", &url
);
295 message
->FindBool("select", &select
);
296 _CreateNewTab(window
, url
, select
);
301 fDownloadWindow
->SetMinimizeOnClose(false);
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
);
313 case SHOW_DOWNLOAD_WINDOW
:
314 _ShowWindow(message
, fDownloadWindow
);
316 case SHOW_SETTINGS_WINDOW
:
317 _ShowWindow(message
, fSettingsWindow
);
319 case SHOW_CONSOLE_WINDOW
:
320 _ShowWindow(message
, fConsoleWindow
);
322 case SHOW_COOKIE_WINDOW
:
323 _ShowWindow(message
, fCookieWindow
);
325 case ADD_CONSOLE_MESSAGE
:
326 fConsoleWindow
->PostMessage(message
);
330 BApplication::MessageReceived(message
);
337 BrowserApp::RefsReceived(BMessage
* message
)
340 delete fLaunchRefsMessage
;
341 fLaunchRefsMessage
= new BMessage(*message
);
345 _RefsReceived(message
);
350 BrowserApp::QuitRequested()
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();
359 if (fWindowCount
== 0) {
360 if (fDownloadWindow
->Lock()) {
361 fDownloadWindow
->SetWorkspaces(1 << current_workspace());
362 if (fDownloadWindow
->IsHidden())
363 fDownloadWindow
->Show();
365 fDownloadWindow
->Activate();
366 fDownloadWindow
->SetMinimizeOnClose(true);
367 fDownloadWindow
->Unlock();
375 fSession
->MakeEmpty();
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
;
382 status_t ret
= message
->FindMessage("window", &windowMessage
);
384 fSession
->AddMessage("window", &windowMessage
);
386 for (int i
= 0; BWindow
* window
= WindowAt(i
); i
++) {
387 BrowserWindow
* webWindow
= dynamic_cast<BrowserWindow
*>(window
);
390 if (!webWindow
->Lock())
393 BMessage windowArchive
;
394 webWindow
->Archive(&windowArchive
, true);
395 fSession
->AddMessage("window", &windowArchive
);
397 if (webWindow
->QuitRequested()) {
398 fLastWindowFrame
= webWindow
->WindowFrame();
408 BWebPage::ShutdownOnce();
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();
416 if (fSettingsWindow
->Lock()) {
417 fSettings
->SetValue("settings window frame", fSettingsWindow
->Frame());
418 fSettingsWindow
->Unlock();
420 if (fConsoleWindow
->Lock()) {
421 fSettings
->SetValue("console window frame", fConsoleWindow
->Frame());
422 fConsoleWindow
->Unlock();
424 if (fCookieWindow
->Lock()) {
425 fSettings
->SetValue("cookie window frame", fCookieWindow
->Frame());
426 fCookieWindow
->Unlock();
429 BMessage cookieArchive
;
430 BNetworkCookieJar
& cookieJar
= fContext
->GetCookieJar();
431 cookieJar
.PurgeForExit();
432 if (cookieJar
.Archive(&cookieArchive
) == B_OK
)
433 fCookies
->SetValue("cookies", cookieArchive
);
440 BrowserApp::_RefsReceived(BMessage
* message
, int32
* _pagesCreated
,
443 int32 pagesCreated
= 0;
445 BrowserWindow
* window
= NULL
;
446 if (message
->FindPointer("window", (void**)&window
) != B_OK
)
450 if (message
->FindBool("fullscreen", &fullscreen
) != B_OK
)
454 for (int32 i
= 0; message
->FindRef("refs", i
, &ref
) == B_OK
; i
++) {
455 BEntry
entry(&ref
, true);
459 if (entry
.GetPath(&path
) != B_OK
)
462 window
= _CreateNewPage(url
.UrlString(), window
, fullscreen
,
468 for (int32 i
= 0; message
->FindString("url", i
, &url
) == B_OK
; i
++) {
469 window
= _CreateNewPage(url
, window
, fullscreen
, pagesCreated
== 0);
473 if (_pagesCreated
!= NULL
)
474 *_pagesCreated
= pagesCreated
;
475 if (_fullscreen
!= NULL
)
476 *_fullscreen
= fullscreen
;
481 BrowserApp::_CreateNewPage(const BString
& url
, BrowserWindow
* webWindow
,
482 bool fullscreen
, bool useBlankTab
)
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
);
490 webWindow
->CreateNewTab(url
, true);
491 webWindow
->Activate();
492 webWindow
->CurrentWebView()->MakeFocus(true);
497 // Otherwise, try to find one in the current workspace
498 uint32 workspace
= 1 << current_workspace();
500 bool loadedInWindowOnCurrentWorkspace
= false;
501 for (int i
= 0; BWindow
* window
= WindowAt(i
); i
++) {
502 webWindow
= dynamic_cast<BrowserWindow
*>(window
);
506 if (webWindow
->Lock()) {
507 if (webWindow
->Workspaces() & workspace
) {
508 if (useBlankTab
&& webWindow
->IsBlankTab()) {
509 if (url
.Length() != 0)
510 webWindow
->CurrentWebView()->LoadURL(url
);
512 webWindow
->CreateNewTab(url
, true);
513 webWindow
->Activate();
514 webWindow
->CurrentWebView()->MakeFocus(true);
515 loadedInWindowOnCurrentWorkspace
= true;
519 if (loadedInWindowOnCurrentWorkspace
)
523 // Finally, if no window is available, let's create one.
524 return _CreateNewWindow(url
, fullscreen
);
529 BrowserApp::_CreateNewWindow(const BString
& url
, bool fullscreen
)
531 // Offset the window frame unless this is the first window created in the
533 if (fWindowCount
> 0)
534 fLastWindowFrame
.OffsetBy(20, 20);
535 if (!BScreen().Frame().Contains(fLastWindowFrame
))
536 fLastWindowFrame
.OffsetTo(50, 50);
538 BrowserWindow
* window
= new BrowserWindow(fLastWindowFrame
, fSettings
,
541 window
->ToggleFullscreen();
548 BrowserApp::_CreateNewTab(BrowserWindow
* window
, const BString
& url
,
553 window
->CreateNewTab(url
, select
);
559 BrowserApp::_ShowWindow(const BMessage
* message
, BWindow
* window
)
563 if (message
->FindUInt32("workspaces", &workspaces
) == B_OK
)
564 window
->SetWorkspaces(workspaces
);
565 if (window
->IsHidden())
583 debugger("Exception caught.");