rods%netscape.com 20b4083174 1) Removes the arg of nsIDOMWindow in the nsIWebBrowserPrint calls
2) Adds a couple of new methods and an attr to nsIWebBrowserPrint (navigate, is frameset, & exitPP)
3) Removes all but one method from nsIContentViewerFile.idl/h the remaining call is for print regression testing
4) Removes the "static" implementation of nsIContentViewerFile.h
5) Fixed up nsIContentViewerFile.idl and turned it back on so it is now generating the header file
6) Removed all uses of nsIContentViewerFile.h except for the WebCrawler (uses it for Printing Regression testing)
7) nsDocumentViewer.cpp now implements nsIWebBrowserPrint.idl this makes it easier to add new print functionality in one place
8) You can now ask an instance of the ContentViewer for a nsIWebBrowserPrint to do printing (it retruns the nsIWebBrowserPrint interface implemented by the nsDocumentViewer)
9) Anybody who was using nsIContentViewerFile to print will now use nsIWebBrowserPrint
10) You can now do a "GetInterface()" on a GlobalWindow for a nsIWebBrowserPrint
11) The browser UI now uses the GetInterface on the GlobalWindow to get a nsIWebBrowserPrint object to do printing and this can be used for all printing functionality
Bug 120622 r=dcone sr=waterson


git-svn-id: svn://10.0.0.236/trunk@113419 18797224-902f-48f8-a5cc-f745e15eee43
2002-02-01 14:52:11 +00:00

1404 lines
43 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Doug Turner <dougt@netscape.com>
* Adam Lock <adamlock@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdio.h>
#include "stdafx.h"
// Win32 header files
#include "windows.h"
#include "commctrl.h"
#include "commdlg.h"
// Mozilla header files
#include "nsEmbedAPI.h"
#include "nsWeakReference.h"
#include "nsIClipboardCommands.h"
#include "nsXPIDLString.h"
#include "nsIWebBrowserPersist.h"
#include "nsIWebBrowserFocus.h"
#include "nsIWindowWatcher.h"
#include "nsIProfile.h"
#include "nsIObserverService.h"
#include "nsIObserver.h"
#include "nsIProfileChangeStatus.h"
#include "nsIURI.h"
#include "plstr.h"
#include "nsIInterfaceRequestor.h"
// Local header files
#include "winEmbed.h"
#include "WebBrowserChrome.h"
#include "WindowCreator.h"
#include "resource.h"
// Printing header files
#include "nsIPrintSettings.h"
#include "nsIWebBrowserPrint.h"
#define MAX_LOADSTRING 100
const TCHAR *szWindowClass = _T("WINEMBED");
// Foward declarations of functions included in this code module:
static ATOM MyRegisterClass(HINSTANCE hInstance);
static LRESULT CALLBACK BrowserWndProc(HWND, UINT, WPARAM, LPARAM);
static BOOL CALLBACK BrowserDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static nsresult InitializeWindowCreator();
static nsresult OpenWebPage(const char * url);
static nsresult ResizeEmbedding(nsIWebBrowserChrome* chrome);
// Profile chooser stuff
static BOOL ChooseNewProfile(BOOL bShowForMultipleProfilesOnly, const char *szDefaultProfile);
static LRESULT CALLBACK ChooseProfileDlgProc(HWND, UINT, WPARAM, LPARAM);
// Global variables
static UINT gDialogCount = 0;
static BOOL gProfileSwitch = FALSE;
static HINSTANCE ghInstanceResources = NULL;
static HINSTANCE ghInstanceApp = NULL;
static char gFirstURL[1024];
// A list of URLs to populate the URL drop down list with
static const TCHAR *gDefaultURLs[] =
{
_T("http://www.mozilla.org/"),
_T("http://www.netscape.com/"),
_T("http://browsertest.web.aol.com/tests/javascript/javascpt/index.htm"),
_T("http://127.0.0.1/"),
_T("http://www.yahoo.com/"),
_T("http://www.travelocity.com/"),
_T("http://www.disney.com/"),
_T("http://www.go.com/"),
_T("http://www.google.com/"),
_T("http://www.ebay.com/"),
_T("http://www.shockwave.com/"),
_T("http://www.slashdot.org/"),
_T("http://www.quicken.com/"),
_T("http://www.hotmail.com/"),
_T("http://www.cnn.com/"),
_T("http://www.javasoft.com/")
};
class ProfileChangeObserver : public nsIObserver,
public nsSupportsWeakReference
{
public:
ProfileChangeObserver();
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
};
int main(int argc, char *argv[])
{
printf("\nYou are embedded, man!\n\n");
// Sophisticated command-line parsing in action
char *szFirstURL = "http://www.mozilla.org/projects/embedding";
char *szDefaultProfile = nsnull;
int argn;
for (argn = 1; argn < argc; argn++)
{
if (stricmp("-P", argv[argn]) == 0)
{
if (argn + 1 < argc)
{
szDefaultProfile = argv[++argn];
}
}
else
{
szFirstURL = argv[argn];
}
}
strncpy(gFirstURL, szFirstURL, sizeof(gFirstURL) - 1);
ghInstanceApp = GetModuleHandle(NULL);
ghInstanceResources = GetModuleHandle(NULL);
// Initialize global strings
TCHAR szTitle[MAX_LOADSTRING];
LoadString(ghInstanceResources, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
MyRegisterClass(ghInstanceApp);
// Init Embedding APIs
NS_InitEmbedding(nsnull, nsnull);
// Choose the new profile
if (!ChooseNewProfile(TRUE, szDefaultProfile))
{
NS_TermEmbedding();
return 1;
}
// Now register an observer to watch for profile changes
nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1"));
ProfileChangeObserver *observer = new ProfileChangeObserver;
observer->AddRef();
observerService->AddObserver(NS_STATIC_CAST(nsIObserver *, observer), "profile-approve-change", PR_TRUE);
observerService->AddObserver(NS_STATIC_CAST(nsIObserver *, observer), "profile-change-teardown", PR_TRUE);
observerService->AddObserver(NS_STATIC_CAST(nsIObserver *, observer), "profile-after-change", PR_TRUE);
InitializeWindowCreator();
// Open the initial browser window
OpenWebPage(gFirstURL);
// Main message loop.
// NOTE: We use a fake event and a timeout in order to process idle stuff for
// Mozilla every 1/10th of a second.
PRBool runCondition = PR_TRUE;
WPARAM rv;
rv = AppCallbacks::RunEventLoop(runCondition);
observer->Release();
// Close down Embedding APIs
NS_TermEmbedding();
return rv;
}
//-----------------------------------------------------------------------------
// ProfileChangeObserver
//-----------------------------------------------------------------------------
NS_IMPL_THREADSAFE_ISUPPORTS2(ProfileChangeObserver, nsIObserver, nsISupportsWeakReference);
ProfileChangeObserver::ProfileChangeObserver()
{
NS_INIT_REFCNT();
}
// ---------------------------------------------------------------------------
// CMfcEmbedApp : nsIObserver
// ---------------------------------------------------------------------------
NS_IMETHODIMP ProfileChangeObserver::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
{
nsresult rv = NS_OK;
if (nsCRT::strcmp(aTopic, "profile-approve-change") == 0)
{
// The profile is about to change!
// Ask the user if they want to
int result = ::MessageBox(NULL, "Do you want to close all windows in order to switch the profile?", "Confirm", MB_YESNO | MB_ICONQUESTION);
if (result != IDYES)
{
nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);
NS_ENSURE_TRUE(status, NS_ERROR_FAILURE);
status->VetoChange();
}
}
else if (nsCRT::strcmp(aTopic, "profile-change-teardown") == 0)
{
// The profile is changing!
// Prevent WM_QUIT by incrementing the dialog count
gDialogCount++;
}
else if (nsCRT::strcmp(aTopic, "profile-after-change") == 0)
{
// Decrease the dialog count so WM_QUIT can once more happen
gDialogCount--;
if (gDialogCount == 0)
{
// All the dialogs have been torn down so open new page
OpenWebPage(gFirstURL);
}
else
{
// The profile has changed, but dialogs are still being
// torn down. Set this flag so when the last one goes
// it can finish the switch.
gProfileSwitch = TRUE;
}
}
return rv;
}
/* InitializeWindowCreator creates and hands off an object with a callback
to a window creation function. This is how all new windows are opened,
except any created directly by the embedding app. */
nsresult InitializeWindowCreator()
{
// create an nsWindowCreator and give it to the WindowWatcher service
WindowCreator *creatorCallback = new WindowCreator();
if (creatorCallback)
{
nsCOMPtr<nsIWindowCreator> windowCreator(dont_QueryInterface(NS_STATIC_CAST(nsIWindowCreator *, creatorCallback)));
if (windowCreator)
{
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
if (wwatch)
{
wwatch->SetWindowCreator(windowCreator);
return NS_OK;
}
}
}
return NS_ERROR_FAILURE;
}
//-----------------------------------------------------------------------------
//
// FUNCTION: OpenWebPage()
//
// PURPOSE: Opens a new browser dialog and starts it loading to the
// specified url.
//
nsresult OpenWebPage(const char *url)
{
nsresult rv;
// Create the chrome object. Note that it leaves this function
// with an extra reference so that it can released correctly during
// destruction (via Win32UI::Destroy)
nsCOMPtr<nsIWebBrowserChrome> chrome;
rv = AppCallbacks::CreateBrowserWindow(nsIWebBrowserChrome::CHROME_ALL,
nsnull, getter_AddRefs(chrome));
if (NS_SUCCEEDED(rv))
{
// Start loading a page
nsCOMPtr<nsIWebBrowser> newBrowser;
chrome->GetWebBrowser(getter_AddRefs(newBrowser));
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(newBrowser));
return webNav->LoadURI(NS_ConvertASCIItoUCS2(url).get(),
nsIWebNavigation::LOAD_FLAGS_NONE,
nsnull,
nsnull,
nsnull);
}
return rv;
}
//
// FUNCTION: GetBrowserFromChrome()
//
// PURPOSE: Returns the HWND for the webbrowser container associated
// with the specified chrome.
//
HWND GetBrowserFromChrome(nsIWebBrowserChrome *aChrome)
{
if (!aChrome)
{
return NULL;
}
nsCOMPtr<nsIEmbeddingSiteWindow> baseWindow = do_QueryInterface(aChrome);
HWND hwnd = NULL;
baseWindow->GetSiteWindow((void **) & hwnd);
return hwnd;
}
//
// FUNCTION: GetBrowserDlgFromChrome()
//
// PURPOSE: Returns the HWND for the browser dialog associated with
// the specified chrome.
//
HWND GetBrowserDlgFromChrome(nsIWebBrowserChrome *aChrome)
{
return GetParent(GetBrowserFromChrome(aChrome));
}
//
// FUNCTION: SaveWebPage()
//
// PURPOSE: Saves the contents of the web page to a file
//
void SaveWebPage(nsIWebBrowser *aWebBrowser)
{
// Use the browser window title as the initial file name
nsCOMPtr<nsIBaseWindow> webBrowserAsWin = do_QueryInterface(aWebBrowser);
nsXPIDLString windowTitle;
webBrowserAsWin->GetTitle(getter_Copies(windowTitle));
nsCString fileName; fileName.AssignWithConversion(windowTitle);
// Sanitize the title of all illegal characters
fileName.CompressWhitespace(); // Remove whitespace from the ends
fileName.StripChars("\\*|:\"><?"); // Strip illegal characters
fileName.ReplaceChar('.', L'_'); // Dots become underscores
fileName.ReplaceChar('/', L'-'); // Forward slashes become hyphens
// Copy filename to a character buffer
char szFile[_MAX_PATH];
memset(szFile, 0, sizeof(szFile));
PL_strncpyz(szFile, fileName.get(), sizeof(szFile) - 1); // XXXldb probably should be just sizeof(szfile)
// Initialize the file save as information structure
OPENFILENAME saveFileNameInfo;
memset(&saveFileNameInfo, 0, sizeof(saveFileNameInfo));
saveFileNameInfo.lStructSize = sizeof(saveFileNameInfo);
saveFileNameInfo.hwndOwner = NULL;
saveFileNameInfo.hInstance = NULL;
saveFileNameInfo.lpstrFilter =
"Web Page, HTML Only (*.htm;*.html)\0*.htm;*.html\0"
"Web Page, Complete (*.htm;*.html)\0*.htm;*.html\0"
"Text File (*.txt)\0*.txt\0";
saveFileNameInfo.lpstrCustomFilter = NULL;
saveFileNameInfo.nMaxCustFilter = NULL;
saveFileNameInfo.nFilterIndex = 1;
saveFileNameInfo.lpstrFile = szFile;
saveFileNameInfo.nMaxFile = sizeof(szFile);
saveFileNameInfo.lpstrFileTitle = NULL;
saveFileNameInfo.nMaxFileTitle = 0;
saveFileNameInfo.lpstrInitialDir = NULL;
saveFileNameInfo.lpstrTitle = NULL;
saveFileNameInfo.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
saveFileNameInfo.nFileOffset = NULL;
saveFileNameInfo.nFileExtension = NULL;
saveFileNameInfo.lpstrDefExt = "htm";
saveFileNameInfo.lCustData = NULL;
saveFileNameInfo.lpfnHook = NULL;
saveFileNameInfo.lpTemplateName = NULL;
if (GetSaveFileName(&saveFileNameInfo))
{
// Does the user want to save the complete document including
// all frames, images, scripts, stylesheets etc. ?
char *pszDataPath = NULL;
if (saveFileNameInfo.nFilterIndex == 2) // 2nd choice means save everything
{
static char szDataFile[_MAX_PATH];
char szDataPath[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath(szFile, drive, dir, fname, ext);
sprintf(szDataFile, "%s_files", fname);
_makepath(szDataPath, drive, dir, szDataFile, "");
pszDataPath = szDataPath;
}
// Save away
nsCOMPtr<nsIWebBrowserPersist> persist(do_QueryInterface(aWebBrowser));
nsCOMPtr<nsILocalFile> file;
NS_NewLocalFile(szFile, TRUE, getter_AddRefs(file));
nsCOMPtr<nsILocalFile> dataPath;
if (pszDataPath)
{
NS_NewLocalFile(pszDataPath, TRUE, getter_AddRefs(dataPath));
}
persist->SaveDocument(nsnull, file, dataPath, nsnull, 0, 0);
}
}
//
// FUNCTION: ResizeEmbedding()
//
// PURPOSE: Resizes the webbrowser window to fit its container.
//
nsresult ResizeEmbedding(nsIWebBrowserChrome* chrome)
{
if (!chrome)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIEmbeddingSiteWindow> embeddingSite = do_QueryInterface(chrome);
HWND hWnd;
embeddingSite->GetSiteWindow((void **) & hWnd);
if (!hWnd)
return NS_ERROR_NULL_POINTER;
RECT rect;
GetClientRect(hWnd, &rect);
// Make sure the browser is visible and sized
nsCOMPtr<nsIWebBrowser> webBrowser;
chrome->GetWebBrowser(getter_AddRefs(webBrowser));
nsCOMPtr<nsIBaseWindow> webBrowserAsWin = do_QueryInterface(webBrowser);
if (webBrowserAsWin)
{
webBrowserAsWin->SetPositionAndSize(rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
PR_TRUE);
webBrowserAsWin->SetVisibility(PR_TRUE);
}
return NS_OK;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof(wcex));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC) BrowserWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(ghInstanceResources, (LPCTSTR)IDI_WINEMBED);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(ghInstanceResources, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: UpdateUI()
//
// PURPOSE: Refreshes the buttons and menu items in the browser dialog
//
void UpdateUI(nsIWebBrowserChrome *aChrome)
{
HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
nsCOMPtr<nsIWebBrowser> webBrowser;
nsCOMPtr<nsIWebNavigation> webNavigation;
aChrome->GetWebBrowser(getter_AddRefs(webBrowser));
webNavigation = do_QueryInterface(webBrowser);
PRBool canGoBack = PR_FALSE;
PRBool canGoForward = PR_FALSE;
if (webNavigation)
{
webNavigation->GetCanGoBack(&canGoBack);
webNavigation->GetCanGoForward(&canGoForward);
}
PRBool canCutSelection = PR_FALSE;
PRBool canCopySelection = PR_FALSE;
PRBool canPaste = PR_FALSE;
nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
if (clipCmds)
{
clipCmds->CanCutSelection(&canCutSelection);
clipCmds->CanCopySelection(&canCopySelection);
clipCmds->CanPaste(&canPaste);
}
HMENU hmenu = GetMenu(hwndDlg);
if (hmenu)
{
EnableMenuItem(hmenu, MOZ_GoBack, MF_BYCOMMAND |
((canGoBack) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
EnableMenuItem(hmenu, MOZ_GoForward, MF_BYCOMMAND |
((canGoForward) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
EnableMenuItem(hmenu, MOZ_Cut, MF_BYCOMMAND |
((canCutSelection) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
EnableMenuItem(hmenu, MOZ_Copy, MF_BYCOMMAND |
((canCopySelection) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
EnableMenuItem(hmenu, MOZ_Paste, MF_BYCOMMAND |
((canPaste) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
}
HWND button;
button = GetDlgItem(hwndDlg, IDC_BACK);
if (button)
EnableWindow(button, canGoBack);
button = GetDlgItem(hwndDlg, IDC_FORWARD);
if (button)
EnableWindow(button, canGoForward);
}
//
// FUNCTION: BrowserDlgProc()
//
// PURPOSE: Browser dialog windows message handler.
//
// COMMENTS:
//
// The code for handling buttons and menu actions is here.
//
BOOL CALLBACK BrowserDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_COMMAND && LOWORD(wParam) == MOZ_SwitchProfile)
{
ChooseNewProfile(FALSE, NULL);
return FALSE;
}
// Get the browser and other pointers since they are used a lot below
HWND hwndBrowser = GetDlgItem(hwndDlg, IDC_BROWSER);
nsIWebBrowserChrome *chrome = nsnull ;
if (hwndBrowser)
{
chrome = (nsIWebBrowserChrome *) GetWindowLong(hwndBrowser, GWL_USERDATA);
}
nsCOMPtr<nsIWebBrowser> webBrowser;
nsCOMPtr<nsIWebNavigation> webNavigation;
nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
if (chrome)
{
chrome->GetWebBrowser(getter_AddRefs(webBrowser));
webNavigation = do_QueryInterface(webBrowser);
webBrowserPrint = do_GetInterface(webBrowser);
}
// Test the message
switch (uMsg)
{
case WM_INITDIALOG:
return TRUE;
case WM_INITMENU:
UpdateUI(chrome);
return TRUE;
case WM_SYSCOMMAND:
if (wParam == SC_CLOSE)
{
WebBrowserChromeUI::Destroy(chrome);
return TRUE;
}
break;
case WM_DESTROY:
return TRUE;
case WM_COMMAND:
if (!webBrowser)
{
return TRUE;
}
// Test which command was selected
switch (LOWORD(wParam))
{
case IDC_ADDRESS:
if (HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam) == CBN_SELCHANGE)
{
// User has changed the address field so enable the Go button
EnableWindow(GetDlgItem(hwndDlg, IDC_GO), TRUE);
}
break;
case IDC_GO:
{
TCHAR szURL[2048];
memset(szURL, 0, sizeof(szURL));
GetDlgItemText(hwndDlg, IDC_ADDRESS, szURL,
sizeof(szURL) / sizeof(szURL[0]) - 1);
webNavigation->LoadURI(
NS_ConvertASCIItoUCS2(szURL).get(),
nsIWebNavigation::LOAD_FLAGS_NONE,
nsnull,
nsnull,
nsnull);
}
break;
case IDC_STOP:
webNavigation->Stop(nsIWebNavigation::STOP_ALL);
UpdateUI(chrome);
break;
case IDC_RELOAD:
webNavigation->Reload(nsIWebNavigation::LOAD_FLAGS_NONE);
break;
case IDM_EXIT:
PostMessage(hwndDlg, WM_SYSCOMMAND, SC_CLOSE, 0);
break;
// File menu commands
case MOZ_NewBrowser:
OpenWebPage(gFirstURL);
break;
case MOZ_Save:
SaveWebPage(webBrowser);
break;
case MOZ_Print:
{
// NOTE: Embedding code shouldn't need to get the docshell or
// contentviewer AT ALL. This code below will break one
// day but will have to do until the embedding API has
// a cleaner way to do the same thing.
if (webBrowserPrint)
{
nsCOMPtr<nsIPrintSettings> printSettings;
webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
NS_ASSERTION(printSettings, "You can't PrintPreview without a PrintSettings!");
if (printSettings)
{
printSettings->SetPrintSilent(PR_TRUE);
webBrowserPrint->Print(printSettings, (nsIWebProgressListener*)nsnull);
}
}
}
break;
// Edit menu commands
case MOZ_Cut:
{
nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
clipCmds->CutSelection();
}
break;
case MOZ_Copy:
{
nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
clipCmds->CopySelection();
}
break;
case MOZ_Paste:
{
nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
clipCmds->Paste();
}
break;
case MOZ_SelectAll:
{
nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
clipCmds->SelectAll();
}
break;
case MOZ_SelectNone:
{
nsCOMPtr<nsIClipboardCommands> clipCmds = do_GetInterface(webBrowser);
clipCmds->SelectNone();
}
break;
// Go menu commands
case IDC_BACK:
case MOZ_GoBack:
webNavigation->GoBack();
UpdateUI(chrome);
break;
case IDC_FORWARD:
case MOZ_GoForward:
webNavigation->GoForward();
UpdateUI(chrome);
break;
// Help menu commands
case MOZ_About:
{
TCHAR szAboutTitle[MAX_LOADSTRING];
TCHAR szAbout[MAX_LOADSTRING];
LoadString(ghInstanceResources, IDS_ABOUT_TITLE, szAboutTitle, MAX_LOADSTRING);
LoadString(ghInstanceResources, IDS_ABOUT, szAbout, MAX_LOADSTRING);
MessageBox(NULL, szAbout, szAboutTitle, MB_OK);
}
break;
}
return TRUE;
case WM_ACTIVATE:
{
nsCOMPtr<nsIWebBrowserFocus> focus(do_GetInterface(webBrowser));
if(focus)
{
switch (wParam)
{
case WA_ACTIVE:
focus->Activate();
break;
case WA_INACTIVE:
focus->Deactivate();
break;
default:
break;
}
}
}
break;
case WM_SIZE:
{
UINT newDlgWidth = LOWORD(lParam);
UINT newDlgHeight = HIWORD(lParam);
// TODO Reposition the control bar - for the moment it's fixed size
// Reposition the status area. Status bar
// gets any space that the fixed size progress bar doesn't use.
int progressWidth;
int statusWidth;
int statusHeight;
HWND hwndStatus = GetDlgItem(hwndDlg, IDC_STATUS);
if (hwndStatus) {
RECT rcStatus;
GetWindowRect(hwndStatus, &rcStatus);
statusHeight = rcStatus.bottom - rcStatus.top;
} else
statusHeight = 0;
HWND hwndProgress = GetDlgItem(hwndDlg, IDC_PROGRESS);
if (hwndProgress) {
RECT rcProgress;
GetWindowRect(hwndProgress, &rcProgress);
progressWidth = rcProgress.right - rcProgress.left;
} else
progressWidth = 0;
statusWidth = newDlgWidth - progressWidth;
if (hwndStatus)
SetWindowPos(hwndStatus,
HWND_TOP,
0, newDlgHeight - statusHeight,
statusWidth,
statusHeight,
SWP_NOZORDER);
if (hwndProgress)
SetWindowPos(hwndProgress,
HWND_TOP,
statusWidth, newDlgHeight - statusHeight,
0, 0,
SWP_NOSIZE | SWP_NOZORDER);
// Resize the browser area (assuming the browse is
// sandwiched between the control bar and status area)
RECT rcBrowser;
POINT ptBrowser;
GetWindowRect(hwndBrowser, &rcBrowser);
ptBrowser.x = rcBrowser.left;
ptBrowser.y = rcBrowser.top;
ScreenToClient(hwndDlg, &ptBrowser);
int browserHeight = newDlgHeight - ptBrowser.y - statusHeight;
if (browserHeight < 1)
{
browserHeight = 1;
}
SetWindowPos(hwndBrowser,
HWND_TOP,
0, 0,
newDlgWidth,
newDlgHeight - ptBrowser.y - statusHeight,
SWP_NOMOVE | SWP_NOZORDER);
}
return TRUE;
}
return FALSE;
}
//
// FUNCTION: BrowserWndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the browser container window.
//
LRESULT CALLBACK BrowserWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
nsIWebBrowserChrome *chrome = (nsIWebBrowserChrome *) GetWindowLong(hWnd, GWL_USERDATA);
switch (message)
{
case WM_SIZE:
// Resize the embedded browser
ResizeEmbedding(chrome);
return 0;
case WM_ERASEBKGND:
// Reduce flicker by not painting the non-visible background
return 1;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
///////////////////////////////////////////////////////////////////////////////
// Profile chooser dialog
//
// FUNCTION: ChooseNewProfile()
//
// PURPOSE: Allows the user to select a new profile from a list.
// The bShowForMultipleProfilesOnly argument specifies whether the
// function should automatically select the first profile and return
// without displaying a dialog box if there is only one profile to
// select.
//
BOOL ChooseNewProfile(BOOL bShowForMultipleProfilesOnly, const char *szDefaultProfile)
{
nsresult rv;
nsCOMPtr<nsIProfile> profileService =
do_GetService(NS_PROFILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
return FALSE;
}
if (szDefaultProfile)
{
// Make a new default profile
nsAutoString newProfileName; newProfileName.AssignWithConversion(szDefaultProfile);
rv = profileService->CreateNewProfile(newProfileName.get(), nsnull, nsnull, PR_FALSE);
if (NS_FAILED(rv)) return FALSE;
rv = profileService->SetCurrentProfile(newProfileName.get());
if (NS_FAILED(rv)) return FALSE;
return TRUE;
}
PRInt32 profileCount = 0;
rv = profileService->GetProfileCount(&profileCount);
if (profileCount == 0)
{
// Make a new default profile
NS_NAMED_LITERAL_STRING(newProfileName, "winEmbed");
rv = profileService->CreateNewProfile(newProfileName.get(), nsnull, nsnull, PR_FALSE);
if (NS_FAILED(rv)) return FALSE;
rv = profileService->SetCurrentProfile(newProfileName.get());
if (NS_FAILED(rv)) return FALSE;
return TRUE;
}
else if (profileCount == 1 && bShowForMultipleProfilesOnly)
{
// GetCurrentProfile returns the profile which was last used but is not nescesarily
// active. Call SetCurrentProfile to make it installed and active.
nsXPIDLString currProfileName;
rv = profileService->GetCurrentProfile(getter_Copies(currProfileName));
if (NS_FAILED(rv)) return FALSE;
rv = profileService->SetCurrentProfile(currProfileName);
if (NS_FAILED(rv)) return FALSE;
return TRUE;
}
INT nResult;
nResult = DialogBox(ghInstanceResources, (LPCTSTR)IDD_CHOOSEPROFILE, NULL, (DLGPROC)ChooseProfileDlgProc);
return (nResult == IDOK) ? TRUE : FALSE;
}
//
// FUNCTION: ChooseProfileDlgProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Dialog handler procedure for the open uri dialog.
//
LRESULT CALLBACK ChooseProfileDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
nsresult rv;
switch (message)
{
case WM_INITDIALOG:
{
HWND hwndProfileList = GetDlgItem(hDlg, IDC_PROFILELIST);
nsCOMPtr<nsIProfile> profileService =
do_GetService(NS_PROFILE_CONTRACTID, &rv);
// Get the list of profile names and add them to the list box
PRUint32 listLen = 0;
PRUnichar **profileList = nsnull;
rv = profileService->GetProfileList(&listLen, &profileList);
for (PRUint32 index = 0; index < listLen; index++)
{
#ifdef UNICODE
SendMessageW(hwndProfileList, LB_ADDSTRING, 0, (LPARAM) profileList[index]);
#else
nsCAutoString profile; profile.AssignWithConversion(profileList[index]);
SendMessageA(hwndProfileList, LB_ADDSTRING, 0, (LPARAM) profile.get());
#endif
}
// Select the current profile (if there is one)
// Get the current profile
#ifdef UNICODE
nsXPIDLString currProfile;
profileService->GetCurrentProfile(getter_Copies(currProfile));
#else
nsXPIDLString currProfileUnicode;
profileService->GetCurrentProfile(getter_Copies(currProfileUnicode));
nsCAutoString currProfile; currProfile.AssignWithConversion(currProfileUnicode);
#endif
// Now find and select it
INT currentProfileIndex = LB_ERR;
currentProfileIndex = SendMessage(hwndProfileList, LB_FINDSTRINGEXACT, -1, (LPARAM) currProfile.get());
if (currentProfileIndex != LB_ERR)
{
SendMessage(hwndProfileList, LB_SETCURSEL, currentProfileIndex, 0);
}
}
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK ||
(HIWORD(wParam) & LBN_DBLCLK && LOWORD(wParam) == IDC_PROFILELIST))
{
HWND hwndProfileList = GetDlgItem(hDlg, IDC_PROFILELIST);
// Get the selected profile from the list box and make it current
INT currentProfileIndex = SendMessage(hwndProfileList, LB_GETCURSEL, 0, 0);
if (currentProfileIndex != LB_ERR)
{
nsCOMPtr<nsIProfile> profileService =
do_GetService(NS_PROFILE_CONTRACTID, &rv);
// Convert TCHAR name to unicode and make it current
INT profileNameLen = SendMessage(hwndProfileList, LB_GETTEXTLEN, currentProfileIndex, 0);
TCHAR *profileName = new TCHAR[profileNameLen + 1];
SendMessage(hwndProfileList, LB_GETTEXT, currentProfileIndex, (LPARAM) profileName);
nsAutoString newProfile; newProfile.AssignWithConversion(profileName);
rv = profileService->SetCurrentProfile(newProfile.get());
}
EndDialog(hDlg, IDOK);
}
else if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
}
return TRUE;
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
// WebBrowserChromeUI
//
// FUNCTION: CreateNativeWindow()
//
// PURPOSE: Creates a new browser dialog.
//
// COMMENTS:
//
// This function loads the browser dialog from a resource template
// and returns the HWND for the webbrowser container dialog item
// to the caller.
//
nativeWindow WebBrowserChromeUI::CreateNativeWindow(nsIWebBrowserChrome* chrome)
{
// Load the browser dialog from resource
HWND hwndDialog;
PRUint32 chromeFlags;
chrome->GetChromeFlags(&chromeFlags);
if ((chromeFlags & nsIWebBrowserChrome::CHROME_ALL) == nsIWebBrowserChrome::CHROME_ALL)
hwndDialog = CreateDialog(ghInstanceResources,
MAKEINTRESOURCE(IDD_BROWSER),
NULL,
BrowserDlgProc);
else
hwndDialog = CreateDialog(ghInstanceResources,
MAKEINTRESOURCE(IDD_BROWSER_NC),
NULL,
BrowserDlgProc);
if (!hwndDialog)
return NULL;
// Stick a menu onto it
if (chromeFlags & nsIWebBrowserChrome::CHROME_MENUBAR) {
HMENU hmenuDlg = LoadMenu(ghInstanceResources, MAKEINTRESOURCE(IDC_WINEMBED));
SetMenu(hwndDialog, hmenuDlg);
} else
SetMenu(hwndDialog, 0);
// Add some interesting URLs to the address drop down
HWND hwndAddress = GetDlgItem(hwndDialog, IDC_ADDRESS);
if (hwndAddress) {
for (int i = 0; i < sizeof(gDefaultURLs) / sizeof(gDefaultURLs[0]); i++)
{
SendMessage(hwndAddress, CB_ADDSTRING, 0, (LPARAM) gDefaultURLs[i]);
}
}
// Fetch the browser window handle
HWND hwndBrowser = GetDlgItem(hwndDialog, IDC_BROWSER);
SetWindowLong(hwndBrowser, GWL_USERDATA, (LONG)chrome); // save the browser LONG_PTR.
SetWindowLong(hwndBrowser, GWL_STYLE, GetWindowLong(hwndBrowser, GWL_STYLE) | WS_CLIPCHILDREN);
gDialogCount++;
return hwndBrowser;
}
//
// FUNCTION: Destroy()
//
// PURPOSE: Destroy the window specified by the chrome
//
void WebBrowserChromeUI::Destroy(nsIWebBrowserChrome* chrome)
{
nsCOMPtr<nsIWebBrowser> webBrowser;
nsCOMPtr<nsIWebNavigation> webNavigation;
chrome->GetWebBrowser(getter_AddRefs(webBrowser));
webNavigation = do_QueryInterface(webBrowser);
if (webNavigation)
webNavigation->Stop(nsIWebNavigation::STOP_ALL);
chrome->ExitModalEventLoop(NS_OK);
HWND hwndDlg = GetBrowserDlgFromChrome(chrome);
if (hwndDlg == NULL)
return;
// Explicitly destroy the embedded browser and then the chrome
// First the browser
nsCOMPtr<nsIWebBrowser> browser = nsnull;
chrome->GetWebBrowser(getter_AddRefs(browser));
nsCOMPtr<nsIBaseWindow> browserAsWin = do_QueryInterface(browser);
if (browserAsWin)
browserAsWin->Destroy();
// Now the chrome
chrome->SetWebBrowser(nsnull);
NS_RELEASE(chrome);
}
//
// FUNCTION: Called as the final act of a chrome object during its destructor
//
void WebBrowserChromeUI::Destroyed(nsIWebBrowserChrome* chrome)
{
HWND hwndDlg = GetBrowserDlgFromChrome(chrome);
if (hwndDlg == NULL)
{
return;
}
// Clear the window user data
HWND hwndBrowser = GetDlgItem(hwndDlg, IDC_BROWSER);
SetWindowLong(hwndBrowser, GWL_USERDATA, nsnull);
DestroyWindow(hwndBrowser);
DestroyWindow(hwndDlg);
--gDialogCount;
if (gDialogCount == 0)
{
if (gProfileSwitch)
{
gProfileSwitch = FALSE;
OpenWebPage(gFirstURL);
}
else
{
// Quit when there are no more browser objects
PostQuitMessage(0);
}
}
}
//
// FUNCTION: Set the input focus onto the browser window
//
void WebBrowserChromeUI::SetFocus(nsIWebBrowserChrome *chrome)
{
HWND hwndDlg = GetBrowserDlgFromChrome(chrome);
if (hwndDlg == NULL)
{
return;
}
HWND hwndBrowser = GetDlgItem(hwndDlg, IDC_BROWSER);
::SetFocus(hwndBrowser);
}
//
// FUNCTION: UpdateStatusBarText()
//
// PURPOSE: Set the status bar text.
//
void WebBrowserChromeUI::UpdateStatusBarText(nsIWebBrowserChrome *aChrome, const PRUnichar* aStatusText)
{
HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
nsCString status;
if (aStatusText)
status.AssignWithConversion(aStatusText);
SetDlgItemText(hwndDlg, IDC_STATUS, status.get());
}
//
// FUNCTION: UpdateCurrentURI()
//
// PURPOSE: Updates the URL address field
//
void WebBrowserChromeUI::UpdateCurrentURI(nsIWebBrowserChrome *aChrome)
{
nsCOMPtr<nsIWebBrowser> webBrowser;
nsCOMPtr<nsIWebNavigation> webNavigation;
aChrome->GetWebBrowser(getter_AddRefs(webBrowser));
webNavigation = do_QueryInterface(webBrowser);
nsCOMPtr<nsIURI> currentURI;
webNavigation->GetCurrentURI(getter_AddRefs(currentURI));
if (currentURI)
{
nsXPIDLCString uriString;
currentURI->GetSpec(getter_Copies(uriString));
HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
SetDlgItemText(hwndDlg, IDC_ADDRESS, uriString.get());
}
}
//
// FUNCTION: UpdateBusyState()
//
// PURPOSE: Refreshes the stop/go buttons in the browser dialog
//
void WebBrowserChromeUI::UpdateBusyState(nsIWebBrowserChrome *aChrome, PRBool aBusy)
{
HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
HWND button;
button = GetDlgItem(hwndDlg, IDC_STOP);
if (button)
EnableWindow(button, aBusy);
button = GetDlgItem(hwndDlg, IDC_GO);
if (button)
EnableWindow(button, !aBusy);
UpdateUI(aChrome);
}
//
// FUNCTION: UpdateProgress()
//
// PURPOSE: Refreshes the progress bar in the browser dialog
//
void WebBrowserChromeUI::UpdateProgress(nsIWebBrowserChrome *aChrome, PRInt32 aCurrent, PRInt32 aMax)
{
HWND hwndDlg = GetBrowserDlgFromChrome(aChrome);
HWND hwndProgress = GetDlgItem(hwndDlg, IDC_PROGRESS);
if (aCurrent < 0)
{
aCurrent = 0;
}
if (aCurrent > aMax)
{
aMax = aCurrent + 20; // What to do?
}
if (hwndProgress)
{
SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0, aMax));
SendMessage(hwndProgress, PBM_SETPOS, aCurrent, 0);
}
}
//
// FUNCTION: ShowContextMenu()
//
// PURPOSE: Display a context menu for the given node
//
void WebBrowserChromeUI::ShowContextMenu(nsIWebBrowserChrome *aChrome, PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
{
// TODO code to test context flags and display a popup menu should go here
}
//
// FUNCTION: ShowTooltip()
//
// PURPOSE: Show a tooltip
//
void WebBrowserChromeUI::ShowTooltip(nsIWebBrowserChrome *aChrome, PRInt32 aXCoords, PRInt32 aYCoords, const PRUnichar *aTipText)
{
// TODO code to show a tooltip should go here
}
//
// FUNCTION: HideTooltip()
//
// PURPOSE: Hide the tooltip
//
void WebBrowserChromeUI::HideTooltip(nsIWebBrowserChrome *aChrome)
{
// TODO code to hide a tooltip should go here
}
void WebBrowserChromeUI::ShowWindow(nsIWebBrowserChrome *aChrome, PRBool aShow)
{
HWND win = GetBrowserDlgFromChrome(aChrome);
::ShowWindow(win, aShow ? SW_RESTORE : SW_HIDE);
}
void WebBrowserChromeUI::SizeTo(nsIWebBrowserChrome *aChrome, PRInt32 aWidth, PRInt32 aHeight)
{
HWND win = GetBrowserDlgFromChrome(aChrome);
RECT winRect;
::GetWindowRect(win, &winRect);
::MoveWindow(win, winRect.left, winRect.top, aWidth, aHeight, TRUE);
}
//
// FUNCTION: GetResourceStringByID()
//
// PURPOSE: Get the resource string for the ID
//
void WebBrowserChromeUI::GetResourceStringById(PRInt32 aID, char ** aReturn)
{
char resBuf[MAX_LOADSTRING];
int retval = LoadString( ghInstanceResources, aID, (LPTSTR)resBuf, sizeof(resBuf) );
if (retval != 0)
{
int resLen = strlen(resBuf);
*aReturn = (char *)calloc(resLen+1, sizeof(char *));
if (!*aReturn) return;
PL_strncpy(*aReturn, (char *) resBuf, resLen);
}
return;
}
//-----------------------------------------------------------------------------
// AppCallbacks
//-----------------------------------------------------------------------------
nsresult AppCallbacks::CreateBrowserWindow(PRUint32 aChromeFlags,
nsIWebBrowserChrome *aParent,
nsIWebBrowserChrome **aNewWindow)
{
WebBrowserChrome * chrome = new WebBrowserChrome();
if (!chrome)
return NS_ERROR_FAILURE;
// the interface to return and one addref, which we assume will be
// immediately released
CallQueryInterface(NS_STATIC_CAST(nsIWebBrowserChrome*, chrome), aNewWindow);
// now an extra addref; the window owns itself (to be released by
// WebBrowserChromeUI::Destroy)
NS_ADDREF(*aNewWindow);
chrome->SetChromeFlags(aChromeFlags);
chrome->SetParent(aParent);
// Insert the browser
nsCOMPtr<nsIWebBrowser> newBrowser;
chrome->CreateBrowser(-1, -1, -1, -1, getter_AddRefs(newBrowser));
if (!newBrowser)
return NS_ERROR_FAILURE;
// Place it where we want it.
ResizeEmbedding(NS_STATIC_CAST(nsIWebBrowserChrome*, chrome));
// Subscribe new window to profile changes so it can kill itself when one happens
nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1"));
if (observerService)
observerService->AddObserver(NS_STATIC_CAST(nsIObserver *, chrome),
"profile-change-teardown", PR_TRUE);
// if opened as chrome, it'll be made visible after the chrome has loaded.
// otherwise, go ahead and show it now.
if (!(aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME))
WebBrowserChromeUI::ShowWindow(*aNewWindow, PR_TRUE);
return NS_OK;
}
void AppCallbacks::EnableChromeWindow(nsIWebBrowserChrome *aWindow,
PRBool aEnabled)
{
HWND hwnd = GetBrowserDlgFromChrome(aWindow);
::EnableWindow(hwnd, aEnabled ? TRUE : FALSE);
}
PRUint32 AppCallbacks::RunEventLoop(PRBool &aRunCondition)
{
MSG msg;
HANDLE hFakeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
while (aRunCondition ) {
// Process pending messages
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
if (!::GetMessage(&msg, NULL, 0, 0)) {
// WM_QUIT
aRunCondition = PR_FALSE;
break;
}
PRBool wasHandled = PR_FALSE;
::NS_HandleEmbeddingEvent(msg, wasHandled);
if (wasHandled)
continue;
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
// Do idle stuff
::MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, 100, QS_ALLEVENTS);
}
::CloseHandle(hFakeEvent);
return msg.wParam;
}