zack%kde.org d3b4ce7cfe Qt Mozilla port. For now the best way to start playing with it is the
TestQGeckoEmbed from the embedding/browser/qt/tests.
Build patch sr=jst, r=biesi.
Rest: r=dbaron,biesi


git-svn-id: svn://10.0.0.236/trunk@163516 18797224-902f-48f8-a5cc-f745e15eee43
2004-10-11 04:01:49 +00:00

468 lines
12 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla 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/MPL/
*
* 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
* Zack Rusin <zack@kde.org>.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Lars Knoll <knoll@kde.org>
* Zack Rusin <zack@kde.org>
*
* 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 MPL, 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 MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "EmbedWindow.h"
#include "qgeckoembed.h"
#include <nsCWebBrowser.h>
#include <nsIComponentManager.h>
#include <nsIDocShellTreeItem.h>
#include "nsIWidget.h"
#include "nsIWebNavigation.h"
#include "nsReadableUtils.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsIDOMEvent.h"
#include <qapplication.h>
#include <qeventloop.h>
#include <qvbox.h>
#include <qwidget.h>
#include <qtooltip.h>
#include <qcursor.h>
#include <qlabel.h>
class MozTipLabel : public QLabel
{
public:
MozTipLabel( QWidget* parent)
: QLabel( parent, "toolTipTip",
Qt::WStyle_StaysOnTop | Qt::WStyle_Customize | Qt::WStyle_NoBorder
| Qt::WStyle_Tool | Qt::WX11BypassWM )
{
setMargin(1);
setAutoMask( FALSE );
setFrameStyle( QFrame::Plain | QFrame::Box );
setLineWidth( 1 );
setAlignment( AlignAuto | AlignTop );
setIndent(0);
polish();
adjustSize();
setFont(QToolTip::font());
setPalette(QToolTip::palette());
}
};
EmbedWindow::EmbedWindow()
: mOwner(nsnull),
mVisibility(PR_FALSE),
mIsModal(PR_FALSE),
tooltip(0)
{
}
EmbedWindow::~EmbedWindow(void)
{
ExitModalEventLoop(PR_FALSE);
if (tooltip)
delete tooltip;
}
void
EmbedWindow::Init(QGeckoEmbed *aOwner)
{
// save our owner for later
mOwner = aOwner;
// create our nsIWebBrowser object and set up some basic defaults.
mWebBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
if (!mWebBrowser) {
//log an error
return;
}
mWebBrowser->SetContainerWindow(NS_STATIC_CAST(nsIWebBrowserChrome *, this));
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(mWebBrowser);
item->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
}
nsresult
EmbedWindow::CreateWindow(void)
{
nsresult rv;
// Get the base window interface for the web browser object and
// create the window.
mBaseWindow = do_QueryInterface(mWebBrowser);
rv = mBaseWindow->InitWindow(mOwner,
nsnull,
0, 0,
mOwner->width(),
mOwner->height());
if (NS_FAILED(rv))
return rv;
rv = mBaseWindow->Create();
if (NS_FAILED(rv))
return rv;
return NS_OK;
}
void
EmbedWindow::ReleaseChildren(void)
{
ExitModalEventLoop(PR_FALSE);
mBaseWindow->Destroy();
mBaseWindow = 0;
mWebBrowser = 0;
}
// nsISupports
NS_IMPL_ADDREF(EmbedWindow)
NS_IMPL_RELEASE(EmbedWindow)
NS_INTERFACE_MAP_BEGIN(EmbedWindow)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus)
NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow)
NS_INTERFACE_MAP_ENTRY(nsITooltipListener)
NS_INTERFACE_MAP_ENTRY(nsIContextMenuListener)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_END
// nsIWebBrowserChrome
NS_IMETHODIMP
EmbedWindow::SetStatus(PRUint32 aStatusType, const PRUnichar *aStatus)
{
switch (aStatusType) {
case STATUS_SCRIPT:
{
mOwner->emitScriptStatus(QString::fromUcs2(aStatus));
}
break;
case STATUS_SCRIPT_DEFAULT:
// Gee, that's nice.
break;
case STATUS_LINK:
{
mLinkMessage = aStatus;
mOwner->emitLinkStatus(QString::fromUcs2(aStatus));
}
break;
}
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::GetWebBrowser(nsIWebBrowser **aWebBrowser)
{
*aWebBrowser = mWebBrowser;
NS_IF_ADDREF(*aWebBrowser);
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::SetWebBrowser(nsIWebBrowser *aWebBrowser)
{
mWebBrowser = aWebBrowser;
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::GetChromeFlags(PRUint32 *aChromeFlags)
{
*aChromeFlags = mOwner->chromeMask();
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::SetChromeFlags(PRUint32 aChromeFlags)
{
mOwner->setChromeMask(aChromeFlags);
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::DestroyBrowserWindow(void)
{
emit mOwner->destroyBrowser();
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
{
emit mOwner->sizeTo(aCX, aCY);
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::ShowAsModal(void)
{
qDebug("setting modal");
mIsModal = PR_TRUE;
qApp->eventLoop()->enterLoop();
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::IsWindowModal(PRBool *_retval)
{
*_retval = mIsModal;
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::ExitModalEventLoop(nsresult aStatus)
{
qDebug("exiting modal");
qApp->eventLoop()->exitLoop();
return NS_OK;
}
// nsIWebBrowserChromeFocus
NS_IMETHODIMP
EmbedWindow::FocusNextElement()
{
//FIXME:
//i think gecko handles that internally
//mOwner->focusNextPrevChild(TRUE);
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::FocusPrevElement()
{
//FIXME: same story as above
//mOwner->focusNextPrevChild(FALSE);
return NS_OK;
}
// nsIEmbeddingSiteWindow
NS_IMETHODIMP
EmbedWindow::SetDimensions(PRUint32 aFlags, PRInt32 aX, PRInt32 aY,
PRInt32 aCX, PRInt32 aCY)
{
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
(aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER |
nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER))) {
return mBaseWindow->SetPositionAndSize(aX, aY, aCX, aCY, PR_TRUE);
}
else if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
return mBaseWindow->SetPosition(aX, aY);
}
else if (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER |
nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)) {
return mBaseWindow->SetSize(aCX, aCY, PR_TRUE);
}
return NS_ERROR_INVALID_ARG;
}
NS_IMETHODIMP
EmbedWindow::GetDimensions(PRUint32 aFlags, PRInt32 *aX,
PRInt32 *aY, PRInt32 *aCX, PRInt32 *aCY)
{
if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION &&
(aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER |
nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER))) {
return mBaseWindow->GetPositionAndSize(aX, aY, aCX, aCY);
}
else if (aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
return mBaseWindow->GetPosition(aX, aY);
}
else if (aFlags & (nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER |
nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER)) {
return mBaseWindow->GetSize(aCX, aCY);
}
return NS_ERROR_INVALID_ARG;
}
NS_IMETHODIMP
EmbedWindow::SetFocus(void)
{
// XXX might have to do more here.
return mBaseWindow->SetFocus();
}
NS_IMETHODIMP
EmbedWindow::GetTitle(PRUnichar **aTitle)
{
*aTitle = ToNewUnicode(mTitle);
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::SetTitle(const PRUnichar *aTitle)
{
mTitle = aTitle;
emit mOwner->windowTitleChanged(QString::fromUcs2(aTitle));
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::GetSiteWindow(void **aSiteWindow)
{
*aSiteWindow = NS_STATIC_CAST(void *, mOwner);
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::GetVisibility(PRBool *aVisibility)
{
*aVisibility = mVisibility;
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::SetVisibility(PRBool aVisibility)
{
// We always set the visibility so that if it's chrome and we finish
// the load we know that we have to show the window.
mVisibility = aVisibility;
// if this is a chrome window and the chrome hasn't finished loading
// yet then don't show the window yet.
if (mOwner->isChrome() && !mOwner->chromeLoaded())
return NS_OK;
emit mOwner->visibilityChanged(aVisibility);
return NS_OK;
}
// nsITooltipListener
NS_IMETHODIMP
EmbedWindow::OnShowTooltip(PRInt32 aXCoords, PRInt32 aYCoords, const PRUnichar *aTipText)
{
QString tipText = QString::fromUcs2(aTipText);
// get the root origin for this content window
nsCOMPtr<nsIWidget> mainWidget;
mBaseWindow->GetMainWidget(getter_AddRefs(mainWidget));
QWidget *window;
window = NS_STATIC_CAST(QWidget*, mainWidget->GetNativeData(NS_NATIVE_WINDOW));
if (!window) {
NS_ERROR("no qt window in hierarchy!\n");
return NS_ERROR_FAILURE;
}
int screen = qApp->desktop()->screenNumber(window);
if (!tooltip || qApp->desktop()->screenNumber(tooltip) != screen) {
delete tooltip;
QWidget *s = QApplication::desktop()->screen(screen);
tooltip = new MozTipLabel(s);
}
tooltip->setText(tipText);
tooltip->resize(tooltip->sizeHint());
QPoint pos(aXCoords, aYCoords+24);
pos = window->mapToGlobal(pos);
tooltip->move(pos);
tooltip->show();
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::OnHideTooltip(void)
{
if (tooltip)
tooltip->hide();
return NS_OK;
}
NS_IMETHODIMP
EmbedWindow::OnShowContextMenu(PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
{
// if (!aEvent->type == NS_CONTEXTMENU)
// return NS_OK;
qDebug("EmbedWindow::OnShowContextMenu");
QString url = mOwner->url();
PRUint16 nodeType;
aNode->GetNodeType(&nodeType);
if (nodeType == nsIDOMNode::ELEMENT_NODE) {
nsIDOMElement *element = static_cast<nsIDOMElement *>(aNode);
nsString tagname;
element->GetTagName(tagname);
nsCString ctagname;
LossyCopyUTF16toASCII(tagname, ctagname);
if (!strcasecmp(ctagname.get(), "a")) {
nsString href;
nsString attr;
attr.AssignLiteral("href");
element->GetAttribute(attr, href);
url = mOwner->resolvedUrl(QString::fromUcs2(href.get()));
} else if (!strcasecmp(ctagname.get(), "img")) {
nsString href;
nsString attr;
attr.AssignLiteral("src");
element->GetAttribute(attr, href);
url = mOwner->resolvedUrl(QString::fromUcs2(href.get()));
}
}
emit mOwner->showContextMenu(QCursor::pos(), url);
return NS_OK;
}
// nsIInterfaceRequestor
NS_IMETHODIMP
EmbedWindow::GetInterface(const nsIID &aIID, void** aInstancePtr)
{
nsresult rv;
rv = QueryInterface(aIID, aInstancePtr);
// pass it up to the web browser object
if (NS_FAILED(rv) || !*aInstancePtr) {
nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(mWebBrowser);
return ir->GetInterface(aIID, aInstancePtr);
}
return rv;
}