/* Copyright (c) 2006-2010, Linden Research, Inc. * * LLQtWebKit Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in GPL-license.txt in this distribution, or online at * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. */ #include #include #include #include #include #include #include #include #include #include "llembeddedbrowserwindow.h" #include "llembeddedbrowserwindow_p.h" #include "llembeddedbrowser.h" #include "llembeddedbrowser_p.h" #include "llnetworkaccessmanager.h" #ifdef STATIC_QT #include // Enable gif and jpeg plugins, since web pages look pretty bleak without gifs or jpegs. // Qt 4.7 uses the system gif and jpeg libraries by default, so this is no longer necessary. // Q_IMPORT_PLUGIN(qgif) // Q_IMPORT_PLUGIN(qjpeg) #ifndef LL_LINUX // Qt also has its own translators for CJK text encodings we need to pull in. Q_IMPORT_PLUGIN(qcncodecs) Q_IMPORT_PLUGIN(qjpcodecs) Q_IMPORT_PLUGIN(qkrcodecs) Q_IMPORT_PLUGIN(qtwcodecs) #endif #endif //#define LLEMBEDDEDBROWSER_DEBUG 1 #ifdef LLEMBEDDEDBROWSER_DEBUG #include #endif #if LL_DARWIN || defined(STATIC_QT) // Don't define qt_sendSpontaneousEvent on the mac -- it causes a multiply-defined symbol. extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); #else #include bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event) { return QCoreApplication::sendSpontaneousEvent(receiver, event); } #endif LLEmbeddedBrowserWindow::LLEmbeddedBrowserWindow() { d = new LLEmbeddedBrowserWindowPrivate(); d->mPage = new LLWebPage; d->mInspector = new QWebInspector; d->mInspector->setPage(d->mPage); d->mPage->window = this; d->mView = new LLWebView; d->mPage->webView = d->mView; d->mView->window = this; d->mView->setPage(d->mPage); d->mGraphicsScene = new LLGraphicsScene; d->mGraphicsScene->window = this; d->mGraphicsView = new QGraphicsView; d->mGraphicsScene->addItem(d->mView); d->mGraphicsView->setScene(d->mGraphicsScene); d->mGraphicsScene->setStickyFocus(true); d->mGraphicsView->viewport()->setParent(0); mEnableLoadingOverlay = false; } LLEmbeddedBrowserWindow::~LLEmbeddedBrowserWindow() { delete d; } void LLEmbeddedBrowserWindow::setParent(LLEmbeddedBrowser* parent) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << parent; #endif d->mParent = parent; if (parent) { d->mPage->setNetworkAccessManager(parent->d->mNetworkAccessManager); } else { d->mPage->setNetworkAccessManager(0); } } void LLEmbeddedBrowserWindow::showWebInspector(bool show) { if ( d ) { if ( d->mInspector ) { d->mInspector->setVisible( show ); } } } void LLEmbeddedBrowserWindow::enableLoadingOverlay(bool enable) { mEnableLoadingOverlay = enable; } // change the background color that gets used between pages (usually white) void LLEmbeddedBrowserWindow::setBackgroundColor(const uint8_t red, const uint8_t green, const uint8_t blue) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << red << green << blue; #endif d->backgroundColor = QColor(red, green, blue); } // void LLEmbeddedBrowserWindow::setEnabled(bool enabled) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << enabled; #endif d->mEnabled = enabled; } // allow consumers of this class to observe events - add themselves as an observer bool LLEmbeddedBrowserWindow::addObserver(LLEmbeddedBrowserWindowObserver* observer) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << observer; #endif return d->mEventEmitter.addObserver(observer); } // allow consumers of this class to observe events - remove themselves as an observer bool LLEmbeddedBrowserWindow::remObserver(LLEmbeddedBrowserWindowObserver* observer) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << observer; #endif return d->mEventEmitter.remObserver(observer); } int LLEmbeddedBrowserWindow::getObserverNumber() { return d->mEventEmitter.getObserverNumber(); } // used by observers of this class to get the current URI std::string& LLEmbeddedBrowserWindow::getCurrentUri() { d->mCurrentUri = llToStdString(d->mPage->mainFrame()->url()); return d->mCurrentUri; } // utility method that is used by observers to retrieve data after an event int16_t LLEmbeddedBrowserWindow::getPercentComplete() { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; #endif return d->mPercentComplete; } // utility method that is used by observers to retrieve data after an event std::string& LLEmbeddedBrowserWindow::getStatusMsg() { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; #endif return d->mStatusText; } // render a page into memory and grab the window unsigned char* LLEmbeddedBrowserWindow::grabWindow(int x, int y, int width, int height) { #if LLEMBEDDEDBROWSER_DEBUG > 10 qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y << width << height; #endif // only grab the window if it's enabled if (!d->mEnabled) return 0; if (!d->mDirty) return d->mPageBuffer; Q_ASSERT(d->mImage.size() == d->mView->size()); if (!d->mPage->mainFrame()->url().isValid()) { d->mImage.fill(d->backgroundColor.value()); } else { QPainter painter(&d->mImage); QRectF r(x, y, width, height); QRect g(0, 0, d->mView->width(), d->mView->height()); d->mGraphicsView->render(&painter, r, g); d->mDirty = false; const bool spinner_enabled = false; if ( spinner_enabled ) { const time_t seconds_before_show_overlay = 1; if ( mEnableLoadingOverlay && d->mShowLoadingOverlay && time(NULL) - d->mTimeLoadStarted >= seconds_before_show_overlay ) { painter.setRenderHint(QPainter::Antialiasing);; QBrush brush; QPen pen; int size = width; if ( height < width ) size = height; const int symbol_translucency = 64; // 0=fully trans, 255=opaque const int symbol_proportion_of_sceen = 8; // (1/8) const int symbol_diameter = size/(symbol_proportion_of_sceen); const int symbol_start_line = symbol_diameter*2/3; const int symbol_end_line = symbol_diameter; const int symbol_num_segments = 20; const int symbol_line_width = size/60; if ( size < 4 ) size = 4; QColor background_color(QColor(128,128,128,symbol_translucency)); brush.setColor(background_color); brush.setStyle(Qt::SolidPattern); pen.setColor(background_color); painter.setPen(pen); painter.setBrush(brush); painter.drawRect(0,0,width, height); painter.translate(QPoint(width/2, height/2)); static int offset=0; painter.rotate(((qreal)(offset++%(symbol_num_segments))/(qreal)symbol_num_segments)*360.0f); for ( int count=0; countmDirty = true; // force dirty so updates happen frequently during load } } painter.end(); if (d->mFlipBitmap) { d->mImage = d->mImage.mirrored(); } d->mImage = d->mImage.rgbSwapped(); } d->mPageBuffer = d->mImage.bits(); return d->mPageBuffer; } // return the buffer that contains the rendered page unsigned char* LLEmbeddedBrowserWindow::getPageBuffer() { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; #endif return d->mPageBuffer; } int16_t LLEmbeddedBrowserWindow::getBrowserWidth() { #if LLEMBEDDEDBROWSER_DEBUG > 10 qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; #endif return d->mImage.width(); } int16_t LLEmbeddedBrowserWindow::getBrowserHeight() { #if LLEMBEDDEDBROWSER_DEBUG > 10 qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; #endif return d->mImage.height(); } int16_t LLEmbeddedBrowserWindow::getBrowserDepth() { #if LLEMBEDDEDBROWSER_DEBUG > 10 qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; #endif return 4; } int32_t LLEmbeddedBrowserWindow::getBrowserRowSpan() { #if LLEMBEDDEDBROWSER_DEBUG > 10 qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; #endif return 4 * getBrowserWidth(); } bool LLEmbeddedBrowserWindow::navigateTo(const std::string uri) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(uri); #endif QUrl url = QUrl::fromUserInput(QString::fromStdString(uri)); d->mPage->triggerAction(QWebPage::Stop); d->mPage->mainFrame()->setUrl(url); d->mPage->mainFrame()->load(url); return true; } bool LLEmbeddedBrowserWindow::userAction(LLQtWebKit::EUserAction action) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << action; #endif bool result = true; switch(action) { case LLQtWebKit::UA_EDIT_CUT: d->mPage->triggerAction(QWebPage::Cut); break; case LLQtWebKit::UA_EDIT_COPY: d->mPage->triggerAction(QWebPage::Copy); break; case LLQtWebKit::UA_EDIT_PASTE: d->mPage->triggerAction(QWebPage::Paste); break; case LLQtWebKit::UA_NAVIGATE_STOP: d->mPage->triggerAction(QWebPage::Stop); break; case LLQtWebKit::UA_NAVIGATE_BACK: d->mPage->triggerAction(QWebPage::Back); break; case LLQtWebKit::UA_NAVIGATE_FORWARD: d->mPage->triggerAction(QWebPage::Forward); break; case LLQtWebKit::UA_NAVIGATE_RELOAD: d->mPage->triggerAction(QWebPage::ReloadAndBypassCache); break; default: result = false; break; } return result; } bool LLEmbeddedBrowserWindow::userActionIsEnabled(LLQtWebKit::EUserAction action) { #if LLEMBEDDEDBROWSER_DEBUG > 10 qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << action; #endif bool result; switch(action) { case LLQtWebKit::UA_EDIT_CUT: result = d->mPage->action(QWebPage::Cut)->isEnabled(); break; case LLQtWebKit::UA_EDIT_COPY: result = d->mPage->action(QWebPage::Copy)->isEnabled(); break; case LLQtWebKit::UA_EDIT_PASTE: result = d->mPage->action(QWebPage::Paste)->isEnabled(); break; case LLQtWebKit::UA_NAVIGATE_STOP: result = true; break; case LLQtWebKit::UA_NAVIGATE_BACK: result = d->mPage->history()->canGoBack(); break; case LLQtWebKit::UA_NAVIGATE_FORWARD: result = d->mPage->history()->canGoForward(); break; case LLQtWebKit::UA_NAVIGATE_RELOAD: result = true; break; default: result = false; break; } return result; } // set the size of the browser window bool LLEmbeddedBrowserWindow::setSize(int16_t width, int16_t height) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << width << height; #endif d->mPageBuffer = NULL; d->mImage = QImage(QSize(width, height), QImage::Format_RGB32); d->mGraphicsView->resize(width, height); d->mView->resize(width, height); d->mImage.fill(d->backgroundColor.rgb()); return true; } bool LLEmbeddedBrowserWindow::flipWindow(bool flip) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << flip; #endif d->mFlipBitmap = flip; return true; } static Qt::KeyboardModifiers convert_modifiers(LLQtWebKit::EKeyboardModifier modifiers) { Qt::KeyboardModifiers result = Qt::NoModifier; if(modifiers & LLQtWebKit::KM_MODIFIER_SHIFT) result |= Qt::ShiftModifier; if(modifiers & LLQtWebKit::KM_MODIFIER_CONTROL) result |= Qt::ControlModifier; if(modifiers & LLQtWebKit::KM_MODIFIER_ALT) result |= Qt::AltModifier; if(modifiers & LLQtWebKit::KM_MODIFIER_META) result |= Qt::MetaModifier; return result; } static Qt::MouseButton qt_button_from_button_number(int button) { Qt::MouseButton result; switch(button) { default: result = Qt::NoButton; break; case 0: result = Qt::LeftButton; break; case 1: result = Qt::RightButton; break; case 2: result = Qt::MidButton; break; case 3: result = Qt::XButton1; break; case 4: result = Qt::XButton2; break; } return result; } static QEvent::Type event_from_mouse_event(LLQtWebKit::EMouseEvent mouse_event) { QEvent::Type result; switch(mouse_event) { default: result = QEvent::None; break; case LLQtWebKit::ME_MOUSE_MOVE: result = QEvent::MouseMove; break; case LLQtWebKit::ME_MOUSE_DOWN: result = QEvent::MouseButtonPress; break; case LLQtWebKit::ME_MOUSE_UP: result = QEvent::MouseButtonRelease; break; case LLQtWebKit::ME_MOUSE_DOUBLE_CLICK: result = QEvent::MouseButtonDblClick; break; } return result; } static QEvent::Type event_from_keyboard_event(LLQtWebKit::EKeyEvent keyboard_event) { QEvent::Type result; switch(keyboard_event) { default: result = QEvent::None; break; case LLQtWebKit::KE_KEY_DOWN: case LLQtWebKit::KE_KEY_REPEAT: result = QEvent::KeyPress; break; case LLQtWebKit::KE_KEY_UP: result = QEvent::KeyRelease; break; } return result; } void LLEmbeddedBrowserWindow::mouseEvent(LLQtWebKit::EMouseEvent mouse_event, int16_t button, int16_t x, int16_t y, LLQtWebKit::EKeyboardModifier modifiers) { #if LLEMBEDDEDBROWSER_DEBUG > 10 qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y; #endif QEvent::Type type = event_from_mouse_event(mouse_event); Qt::MouseButton qt_button = qt_button_from_button_number(button); Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); if(type == QEvent::MouseMove) { // Mouse move events should always use "no button". qt_button = Qt::NoButton; } // FIXME: should the current button state be updated before or after constructing the event? switch(type) { case QEvent::MouseButtonPress: case QEvent::MouseButtonDblClick: d->mCurrentMouseButtonState |= qt_button; break; case QEvent::MouseButtonRelease: d->mCurrentMouseButtonState &= ~qt_button; break; default: break; } QMouseEvent event(type, QPoint(x, y), qt_button, d->mCurrentMouseButtonState, qt_modifiers); qt_sendSpontaneousEvent(d->mGraphicsView->viewport(), &event); } void LLEmbeddedBrowserWindow::scrollWheelEvent(int16_t x, int16_t y, int16_t scroll_x, int16_t scroll_y, LLQtWebKit::EKeyboardModifier modifiers) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y; #endif Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); if(scroll_y != 0) { QWheelEvent event(QPoint(x, y), scroll_y, d->mCurrentMouseButtonState, qt_modifiers, Qt::Vertical); qApp->sendEvent(d->mGraphicsView->viewport(), &event); } if(scroll_x != 0) { QWheelEvent event(QPoint(x, y), scroll_x, d->mCurrentMouseButtonState, qt_modifiers, Qt::Horizontal); qApp->sendEvent(d->mGraphicsView->viewport(), &event); } } // utility methods to set an error message so something else can look at it void LLEmbeddedBrowserWindow::scrollByLines(int16_t lines) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << lines; #endif int currentScrollValue = d->mPage->mainFrame()->scrollBarValue(Qt::Vertical); d->mPage->mainFrame()->setScrollBarValue(Qt::Vertical, currentScrollValue + lines); } // Send a keyboard event with native event data. void LLEmbeddedBrowserWindow::keyboardEvent( LLQtWebKit::EKeyEvent key_event, uint32_t key_code, const char *utf8_text, LLQtWebKit::EKeyboardModifier modifiers, uint32_t native_scan_code, uint32_t native_virtual_key, uint32_t native_modifiers) { QEvent::Type type = event_from_keyboard_event(key_event); Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); bool auto_repeat = (key_event == LLQtWebKit::KE_KEY_REPEAT); QString text = QString::fromUtf8(utf8_text); Qt::Key key = Qt::Key_unknown; switch (key_code) { case LLQtWebKit::KEY_RETURN: key = Qt::Key_Return; break; case LLQtWebKit::KEY_LEFT: key = Qt::Key_Left; break; case LLQtWebKit::KEY_RIGHT: key = Qt::Key_Right; break; case LLQtWebKit::KEY_UP: key = Qt::Key_Up; break; case LLQtWebKit::KEY_DOWN: key = Qt::Key_Down; break; case LLQtWebKit::KEY_ESCAPE: key = Qt::Key_Escape; break; case LLQtWebKit::KEY_BACKSPACE: key = Qt::Key_Backspace; break; case LLQtWebKit::KEY_DELETE: key = Qt::Key_Delete; break; case LLQtWebKit::KEY_SHIFT: key = Qt::Key_Shift; break; case LLQtWebKit::KEY_CONTROL: key = Qt::Key_Control; break; case LLQtWebKit::KEY_ALT: key = Qt::Key_Alt; break; case LLQtWebKit::KEY_HOME: key = Qt::Key_Home; break; case LLQtWebKit::KEY_END: key = Qt::Key_End; break; case LLQtWebKit::KEY_PAGE_UP: key = Qt::Key_PageUp; break; case LLQtWebKit::KEY_PAGE_DOWN: key = Qt::Key_PageDown; break; case LLQtWebKit::KEY_HYPHEN: key = Qt::Key_hyphen; break; case LLQtWebKit::KEY_EQUALS: key = Qt::Key_Equal; break; case LLQtWebKit::KEY_INSERT: key = Qt::Key_Insert; break; case LLQtWebKit::KEY_CAPSLOCK: key = Qt::Key_CapsLock; break; case LLQtWebKit::KEY_TAB: key = Qt::Key_Tab; break; case LLQtWebKit::KEY_ADD: key = Qt::Key_Plus; break; case LLQtWebKit::KEY_SUBTRACT: key = Qt::Key_Minus; break; case LLQtWebKit::KEY_MULTIPLY: key = Qt::Key_Asterisk; break; case LLQtWebKit::KEY_DIVIDE: key = Qt::Key_Slash; break; case LLQtWebKit::KEY_F1: key = Qt::Key_F1; break; case LLQtWebKit::KEY_F2: key = Qt::Key_F2; break; case LLQtWebKit::KEY_F3: key = Qt::Key_F3; break; case LLQtWebKit::KEY_F4: key = Qt::Key_F4; break; case LLQtWebKit::KEY_F5: key = Qt::Key_F5; break; case LLQtWebKit::KEY_F6: key = Qt::Key_F6; break; case LLQtWebKit::KEY_F7: key = Qt::Key_F7; break; case LLQtWebKit::KEY_F8: key = Qt::Key_F8; break; case LLQtWebKit::KEY_F9: key = Qt::Key_F9; break; case LLQtWebKit::KEY_F10: key = Qt::Key_F10; break; case LLQtWebKit::KEY_F11: key = Qt::Key_F11; break; case LLQtWebKit::KEY_F12: key = Qt::Key_F12; break; case LLQtWebKit::KEY_PAD_UP: key = Qt::Key_Up; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_DOWN: key = Qt::Key_Down; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_LEFT: key = Qt::Key_Left; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_RIGHT: key = Qt::Key_Right; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_HOME: key = Qt::Key_Home; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_END: key = Qt::Key_End; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_PGUP: key = Qt::Key_PageUp; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_PGDN: key = Qt::Key_PageDown; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_CENTER: key = Qt::Key_5; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_INS: key = Qt::Key_Insert; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_DEL: key = Qt::Key_Delete; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_RETURN: key = Qt::Key_Enter; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_ADD: key = Qt::Key_Plus; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_SUBTRACT: key = Qt::Key_Minus; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_MULTIPLY: key = Qt::Key_Asterisk; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_PAD_DIVIDE: key = Qt::Key_Slash; qt_modifiers |= Qt::KeypadModifier; break; case LLQtWebKit::KEY_NONE: key = Qt::Key_unknown; break; default: key = (Qt::Key)toupper(key_code); break; } QKeyEvent *event = QKeyEvent::createExtendedKeyEvent( type, key, qt_modifiers, native_scan_code, native_virtual_key, native_modifiers, text, auto_repeat, text.count()); qApp->sendEvent(d->mGraphicsScene, event); delete event; } // give focus to the browser so that input keyboard events work void LLEmbeddedBrowserWindow::focusBrowser(bool focus_browser) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << focus_browser; #endif QEvent ev(QEvent::WindowActivate); qApp->sendEvent(d->mGraphicsScene, &ev); QEvent ev2(QEvent::ActivationChange); qApp->sendEvent(d->mGraphicsScene, &ev2); QFocusEvent event(focus_browser ? QEvent::FocusIn : QEvent::FocusOut, Qt::ActiveWindowFocusReason); qApp->sendEvent(d->mPage, &event); } void LLEmbeddedBrowserWindow::setWindowId(int window_id) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << window_id; #endif d->mWindowId = window_id; } int LLEmbeddedBrowserWindow::getWindowId() { return d->mWindowId; } void LLEmbeddedBrowserWindow::proxyWindowOpened(const std::string target, const std::string uuid) { LLWebPageOpenShim *shim = findShim(uuid); if(!shim) { // We don't already have a shim with this uuid -- create one. shim = new LLWebPageOpenShim(this, d->mPage); d->mProxyPages.push_back(shim); #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow::proxyWindowOpened: page list size is " << d->mProxyPages.size(); #endif } shim->setProxy(target, uuid); } void LLEmbeddedBrowserWindow::proxyWindowClosed(const std::string uuid) { LLWebPageOpenShim *shim = findShim(uuid); if(shim) { deleteShim(shim); } } std::string LLEmbeddedBrowserWindow::evaluateJavaScript(std::string script) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(script); #endif QString q_script = QString::fromStdString(script); QString result = d->mPage->mainFrame()->evaluateJavaScript(q_script).toString(); return llToStdString(result); } void LLEmbeddedBrowserWindow::setHostLanguage(const std::string host_language) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(host_language); #endif if ( d ) if ( d->mPage ) d->mPage->setHostLanguage( host_language ); } void LLEmbeddedBrowserWindow::navigateErrorPage( int http_status_code ) { LLEmbeddedBrowserWindowEvent event(getWindowId()); event.setIntValue( http_status_code ); d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onNavigateErrorPage, event); } void LLEmbeddedBrowserWindow::setNoFollowScheme(std::string scheme) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(scheme); #endif d->mNoFollowScheme = QString::fromStdString(scheme); // The scheme part of the url is what is before '://' d->mNoFollowScheme = d->mNoFollowScheme.mid(0, d->mNoFollowScheme.indexOf("://")); } std::string LLEmbeddedBrowserWindow::getNoFollowScheme() { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; #endif return llToStdString(d->mNoFollowScheme); } void LLEmbeddedBrowserWindow::prependHistoryUrl(std::string url) { #ifdef WEBHISTORYPATCH // *HACK: we only have a URL here, we set a "" title and "current time" as // last visited time. d->mPage->history()->prependItem(QString::fromStdString(url), QString::fromAscii(""), QDateTime::currentDateTime()); #else Q_UNUSED(url); #endif } void LLEmbeddedBrowserWindow::clearHistory() { d->mPage->history()->clear(); } std::string LLEmbeddedBrowserWindow::dumpHistory() { std::ostringstream oss; const QList &items = d->mPage->history()->backItems(9999); oss << "cur: " << d->mPage->history()->currentItemIndex() << ":" << d->mPage->history()->currentItem().url().toString().toAscii().data() << "\n"; for (int i=0; i< items.count(); i++) { oss << items[i].url().toString().toAscii().data() << "\n"; } return oss.str(); } void LLEmbeddedBrowserWindow::cookieChanged(const std::string &cookie, const std::string &url, bool dead) { LLEmbeddedBrowserWindowEvent event(getWindowId()); event.setEventUri(url); event.setStringValue(cookie); event.setIntValue((int)dead); d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onCookieChanged, event); } QWebPage *LLEmbeddedBrowserWindow::createWindow() { QWebPage *result = NULL; if(d->mOpeningSelf) { // Special case: opening self to set target, etc. #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow::createWindow: opening self to set target name. "; #endif result = d->mPage; d->mOpeningSelf = false; } else { LLWebPageOpenShim *shim = new LLWebPageOpenShim(this, d->mPage); d->mProxyPages.push_back(shim); result = shim; #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow::createWindow: page list size is " << d->mProxyPages.size(); #endif } return result; } LLWebPageOpenShim *LLEmbeddedBrowserWindow::findShim(const std::string &uuid) { LLEmbeddedBrowserWindowPrivate::ProxyList::iterator iter; for(iter = d->mProxyPages.begin(); iter != d->mProxyPages.end(); iter++) { if((*iter)->matchesUUID(uuid)) return *iter; } return NULL; } void LLEmbeddedBrowserWindow::deleteShim(LLWebPageOpenShim *shim) { shim->window = 0; shim->deleteLater(); d->mProxyPages.remove(shim); #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow::deleteShim: page list size is " << d->mProxyPages.size(); #endif } void LLEmbeddedBrowserWindow::setTarget(const std::string &target) { #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow::setTarget: setting target to " << QString::fromStdString(target); #endif d->mOpeningSelf = true; std::stringstream s; s << "window.open(\"\",\"" << target << "\");"; evaluateJavaScript(s.str()); } std::string LLEmbeddedBrowserWindow::requestFilePicker() { std::string filename_chosen; LLEmbeddedBrowserWindowEvent event(getWindowId()); event.setEventUri(getCurrentUri()); event.setStringValue("*.png;*.jpg"); // If there's at least one observer registered, call it with the event. LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); if(i != d->mEventEmitter.end()) { filename_chosen = (*i)->onRequestFilePicker(event); } return filename_chosen; } bool LLEmbeddedBrowserWindow::authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) { bool result = false; #ifdef LLEMBEDDEDBROWSER_DEBUG qDebug() << "LLEmbeddedBrowserWindow::authRequest: requesting auth for url " << QString::fromStdString(in_url) << ", realm " << QString::fromStdString(in_realm); #endif // If there's at least one observer registered, send it the auth request. LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); if(i != d->mEventEmitter.end()) { result = (*i)->onAuthRequest(in_url, in_realm, out_username, out_password); } return result; } bool LLEmbeddedBrowserWindow::certError(const std::string &in_url, const std::string &in_msg) { bool result = false; // If there's at least one observer registered, send it the auth request. LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); if(i != d->mEventEmitter.end()) { result = (*i)->onCertError(in_url, in_msg); } return result; } void LLEmbeddedBrowserWindow::onQtDebugMessage( const std::string& msg, const std::string& msg_type) { // If there's at least one observer registered, send it the auth request. LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); if(i != d->mEventEmitter.end()) { (*i)->onQtDebugMessage(msg, msg_type); } } void LLEmbeddedBrowserWindow::setWhiteListRegex( const std::string& regex ) { if ( d ) if ( d->mPage ) d->mPage->setWhiteListRegex( regex ); } // Second Life viewer specific functions void LLEmbeddedBrowserWindow::setSLObjectEnabled( bool enabled ) { if ( d ) if ( d->mPage ) d->mPage->setSLObjectEnabled( enabled ); } void LLEmbeddedBrowserWindow::setAgentLanguage( const std::string& agent_language ) { if ( d ) if ( d->mPage ) d->mPage->setAgentLanguage( agent_language ); } void LLEmbeddedBrowserWindow::setAgentRegion( const std::string& agent_region ) { if ( d ) if ( d->mPage ) d->mPage->setAgentRegion( agent_region ); } void LLEmbeddedBrowserWindow::setAgentLocation( double x, double y, double z ) { if ( d ) if ( d->mPage ) d->mPage->setAgentLocation( x, y, z ); } void LLEmbeddedBrowserWindow::setAgentGlobalLocation( double x, double y, double z ) { if ( d ) if ( d->mPage ) d->mPage->setAgentGlobalLocation( x, y, z ); } void LLEmbeddedBrowserWindow::setAgentOrientation( double angle ) { if ( d ) if ( d->mPage ) d->mPage->setAgentOrientation( angle ); } void LLEmbeddedBrowserWindow::setAgentMaturity( const std::string& agent_maturity ) { if ( d ) if ( d->mPage ) d->mPage->setAgentMaturity( agent_maturity ); } void LLEmbeddedBrowserWindow::emitLocation() { if ( d ) if ( d->mPage ) d->mPage->emitLocation(); } void LLEmbeddedBrowserWindow::emitMaturity() { if ( d ) if ( d->mPage ) d->mPage->emitMaturity(); } void LLEmbeddedBrowserWindow::emitLanguage() { if ( d ) if ( d->mPage ) d->mPage->emitLanguage(); } void LLEmbeddedBrowserWindow::setPageZoomFactor( double factor ) { if ( d ) if ( d->mPage ) d->mPage->setPageZoomFactor( factor ); } LLGraphicsScene::LLGraphicsScene() : QGraphicsScene() , window(0) { connect(this, SIGNAL(changed(const QList &)), this, SLOT(repaintRequestedSlot(const QList &))); } void LLGraphicsScene::repaintRequestedSlot(const QList ®ions) { if (!window) return; window->d->mDirty = true; for (int i = 0; i < regions.count(); ++i) { LLEmbeddedBrowserWindowEvent event(window->getWindowId()); event.setEventUri(window->getCurrentUri()); event.setRectValue(regions[i].x(), regions[i].y(), regions[i].width(), regions[i].height()); window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onPageChanged, event); } } #include #include LLWebView::LLWebView(QGraphicsItem *parent) : QGraphicsWebView(parent) , window(0) { } bool LLWebView::event(QEvent* event) { if (window && event->type() == QEvent::CursorChange) { QCursor cursor = this->cursor(); if (currentShape != cursor.shape()) { currentShape = cursor.shape(); LLQtWebKit::ECursor llcursor; switch(currentShape) { case Qt::ArrowCursor: llcursor = LLQtWebKit::C_ARROW; break; case Qt::PointingHandCursor: llcursor = LLQtWebKit::C_POINTINGHAND; break; case Qt::IBeamCursor: llcursor = LLQtWebKit::C_IBEAM; break; case Qt::SplitVCursor: llcursor = LLQtWebKit::C_SPLITV; break; case Qt::SplitHCursor: llcursor = LLQtWebKit::C_SPLITH; break; default: qWarning() << "Unhandled cursor shape:" << currentShape; llcursor = LLQtWebKit::C_ARROW; } LLEmbeddedBrowserWindowEvent event(window->getWindowId()); event.setEventUri(window->getCurrentUri()); event.setIntValue((int)llcursor); window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onCursorChanged, event); } return true; } return QGraphicsWebView::event(event); } std::string llToStdString(const QString &s) { return llToStdString(s.toUtf8()); } std::string llToStdString(const QByteArray &bytes) { return std::string(bytes.constData(), bytes.size()); } std::string llToStdString(const QUrl &url) { return llToStdString(url.toEncoded()); }