/* * Copyright (c) 2004 Nokia. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Nokia nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "BridgeImpl.h" #include "NRCore/WebCoreViewFactory.h" #include "NRCore/WebCoreSettings.h" #include "NRCore/WebCoreResourceLoader.h" #include "NRCore/WebCoreCache.h" #include "NRCore/WebCoreResponse.h" #include "Http.h" #ifdef _WIN32 #include "Win32Context.h" #include "Win32ContextFactory.h" #include "Win32TextRendererFactory.h" #else #include "GdkXftContext.h" #include "GdkXftContextFactory.h" #include "XftTextRendererFactory.h" #endif #include "ImageRendererFactory.h" #include "VisitedURLHistory.h" #include "CookieStorage.h" #include "UnicodeImpl.h" #include "ResourceLoadListener.h" #include "PageLoadListener.h" #include "osbimpl.h" #include "GdkHelpers.h" #include "GLibHelpers.h" #include "ContentTransposer.h" #include "SynchronousLoader.h" static void mapToParentWindow(GdkWindow* parent, GdkWindow* child, int&x, int&y); extern "C" { static void size_allocate( GtkWidget *widget, GtkAllocation *allocation, gpointer data); static int expose(GtkWidget *widget, GdkEventExpose *event, gpointer data); static gint motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer data); static gint button_press(GtkWidget *widget, GdkEventButton *event, gpointer data); static gint button_release(GtkWidget *widget, GdkEventButton *event, gpointer data); static gboolean focus(GtkWidget *widget, GtkDirectionType dir, gpointer data); static gboolean focus_inout_event(GtkWidget *widget, GdkEventFocus *event, gpointer data); static gboolean key_press_or_release(GtkWidget *widget, GdkEventKey *event, gpointer data); static gboolean expiring_rect_timeout(gpointer user_data); } class FactoryInitializer { public: FactoryInitializer() { WebCoreUnicodeDigitValueFunction = UnicodeImplDigitValueFunction; WebCoreUnicodeDirectionFunction = UnicodeImplDirectionFunction; WebCoreUnicodeMirroredFunction = UnicodeImplMirroredFunction; WebCoreUnicodeMirroredCharFunction = UnicodeImplMirroredCharFunction; WebCoreUnicodeLowerFunction = UnicodeImplLowerFunction; WebCoreUnicodeUpperFunction = UnicodeImplUpperFunction; #ifdef _WIN32 Win32TextRendererFactory::useAsSharedFactory(); Win32ContextFactory::useAsSharedFactory(); #else XftTextRendererFactory::useAsSharedFactory(); GdkXftContextFactory::useAsSharedFactory(); #endif ImageRendererFactory::useAsSharedFactory(); VisitedURLHistory::useAsSharedProvider(); CookieStorage::useAsSharedAdapter(); } }; static FactoryInitializer _fi; extern "C"{ static gboolean focus_scrolledwindow(GtkWidget *widget, GtkDirectionType dir, gpointer data) { #if DEBUG g_printerr("%s: widget:%x dir:%x data:%x \n", __PRETTY_FUNCTION__, (int)widget, (int)dir, (int)data); #endif BridgeImpl *bridge = static_cast(data); return bridge->focus(widget, dir); } static gboolean focus_in_scrolledwindow(GtkWidget *widget, GdkEventFocus *event, gpointer data) { #if DEBUG g_printerr("%s: widget:%x data:%x in:%x\n", __PRETTY_FUNCTION__, (int)widget, (int)data, event->in); #endif if (event->in == FALSE) { // FIXME: How to unset document focus // BridgeImpl *bridge = static_cast(data); } return FALSE; } } static void freeGListOfStrings(GList* listOfStrings) { if (listOfStrings) { GList* iter = listOfStrings; while (iter) { if (iter->data) g_free(iter->data); iter = g_list_next(iter); } g_list_free(listOfStrings); } } BridgeImpl::BridgeImpl(BridgeImpl *parent) :m_parent(parent) ,m_childFrames(0) ,m_documentState(0) ,m_shouldReapplyStyles(false) ,m_inExpose(false) ,m_requestedURI(0) ,m_requestedURIString(0) ,m_currentURI(0) ,m_currentURIString(0) ,m_generatedFrameName(0) ,m_generatedFrameNameId(0) ,m_frameName(0) ,m_activeListener(0) ,m_activeRequest(0) ,m_isReloading(false) ,m_isRedirecting(false) ,m_expiringRects(0) ,m_nextExpiringMoment(0) ,m_nextExpiringId(0) ,m_unfocusView(false) { if (parent) { m_parent = parent; setParent(parent); didSetName("root frame"); } else { m_parent = 0; } WebCoreBridge::init(); WebCoreCache::setDisabled(false); m_oldCanvasSize.x = m_oldCanvasSize.y = m_oldCanvasSize.width = m_oldCanvasSize.height = 0; m_eventBox = gtk_event_box_new(); m_frameWidget = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new(NULL, NULL)); GTK_WIDGET_SET_FLAGS(m_frameWidget, GTK_CAN_FOCUS); gtk_scrolled_window_set_shadow_type(m_frameWidget, GTK_SHADOW_NONE); GtkAdjustment* ha = gtk_scrolled_window_get_hadjustment(m_frameWidget); GtkAdjustment* va = gtk_scrolled_window_get_vadjustment(m_frameWidget); ha->step_increment = 20; va->step_increment = 10; m_frameCanvas = gtk_layout_new(gtk_scrolled_window_get_hadjustment(m_frameWidget), gtk_scrolled_window_get_vadjustment(m_frameWidget)); gtk_widget_set_double_buffered(GTK_WIDGET (m_frameCanvas), FALSE); gtk_widget_set_double_buffered(GTK_WIDGET (m_frameWidget), FALSE); gtk_widget_add_events(GTK_WIDGET (m_frameCanvas), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_EXPOSURE_MASK); gtk_container_add(GTK_CONTAINER (m_frameWidget), m_frameCanvas); gtk_container_add(GTK_CONTAINER (m_eventBox), GTK_WIDGET(m_frameWidget)); m_frameWidget.connect("focus", ::focus_scrolledwindow, this); m_frameWidget.connect("focus-in-event", ::focus_in_scrolledwindow, this); m_frameWidget.connect("focus-out-event", ::focus_in_scrolledwindow, this); connectFrameContents(); createKHTMLViewWithGtkWidget(GTK_WIDGET(m_frameWidget), 0,0); } /** * * Bridge delete semantics: * on deleting top level main frame, the KHTMLPart takes care of subframes. * HTMLFrameElementImpl::detach calls KHTMLPart::frameDetached, which will inform * Bridge that frame is ready to be deleted * Bridge then deletes itself and derefs its part. * After that KHTMLPart::frameDetached removes the part KHTMLPart's subframe list * and derefs the part for the last time. part gets destroyed. */ BridgeImpl::~BridgeImpl() { #ifdef DEBUG g_printerr("%s this:%x, part:%x, frameName:%s", __PRETTY_FUNCTION__, (int)this, (int)part(), m_frameName); #endif if (m_frameName) g_free(m_frameName); if (m_currentURIString) g_free(m_currentURIString); if (m_requestedURIString) g_free(m_requestedURIString); if (m_requestedURI) gnet_uri_delete(m_requestedURI); if (m_currentURI) gnet_uri_delete(m_currentURI); if (m_generatedFrameName) g_free(m_generatedFrameName); if (m_activeListener) delete m_activeListener; clearExpiringRects(); GList* iter = g_list_first(m_childFrames); BridgeImpl* child; while (iter) { child = static_cast(iter->data); assert(child); child->m_parent = 0; iter = g_list_next(iter); } g_list_free(m_childFrames); freeGListOfStrings(m_documentState); disconnectFrameContents(); } BridgeImpl* BridgeImpl::mainFrame() { if (m_parent) return m_parent->mainFrame(); return this; } /** Searches for a child frame from current frame and subframes * internal function * Searches for a child frame from current frame and subframes recursively * @return 0 on failure */ BridgeImpl* BridgeImpl::findChildFrameNamed(const gchar* frameName) { if (strcmp(this->m_frameName, frameName)==0) return this; BridgeImpl* result; GList* iter = g_list_first(m_childFrames); BridgeImpl* child; while (iter) { child = static_cast(iter->data); assert(child); result = child->findChildFrameNamed(frameName); if (result) return result; iter = g_list_next(iter); } return 0; } /** Searches for child frames from current frame, subframes, and parent frames * internal * First searches name from self, then childframes, except asendFrom -branch. * If not found, ascens one level up in the hierarchy */ BridgeImpl* BridgeImpl::ascendingFindFrameNamed(const gchar* frameName, BridgeImpl* ascendFrom) { // search self if (strcmp(this->m_frameName, frameName)==0) return this; BridgeImpl* result = 0; // search subtrees != ascendFrom GList* iter = g_list_first(m_childFrames); BridgeImpl* child; while (iter) { child = static_cast(iter->data); assert(child); if (child != ascendFrom) { result = child->findChildFrameNamed(frameName); if (result) return result; } iter = g_list_next(iter); } // search parent if (m_parent) return m_parent->ascendingFindFrameNamed(frameName, this); return 0; } WebCoreBridge* BridgeImpl::findFrameNamed(const gchar *frameName) { // search common names if (strcmp(frameName, "_top")==0) return mainFrame(); if (strcmp(frameName,"m_parent")==0) return m_parent ? m_parent : this; if (strcmp(frameName,"_self")==0) return this; // search self if (this->m_frameName == frameName) return this; BridgeImpl* result = 0; // search subframes result = findChildFrameNamed(frameName); if (result) return result; // search upper branches if (m_parent) { result = m_parent->ascendingFindFrameNamed(frameName, this); if (result) return result; } // search other peers BridgeImpl *thisMain = mainFrame(); GList* myPeers = thisMain->peers(); GList* iter = g_list_first(myPeers); BridgeImpl *child; while (iter) { child = static_cast(iter->data); if (thisMain != child) { // skip this windows' branch, already searched result = child->findChildFrameNamed(frameName); if (result) return result; } iter = g_list_next(iter); } return 0; } const gchar* BridgeImpl::generateFrameName() { static gchar* templ = ""; // doesn't this leak one duplicated string? if (m_generatedFrameName) g_free(m_generatedFrameName); m_generatedFrameName = g_strdup_printf(templ, m_generatedFrameNameId); m_generatedFrameNameId++; return m_generatedFrameName; } void BridgeImpl::frameDetached() { if (m_parent) { m_parent->m_childFrames = g_list_remove(m_parent->m_childFrames, this); } delete(this); } GtkWidget* BridgeImpl::documentView() { return GTK_WIDGET (m_frameWidget); } void BridgeImpl::commitLoad() { setCurrentURI(m_requestedURIString); emitCommitLoad(); } // methods overrides default WebCore method. void BridgeImpl::openURL(const gchar *_URL, bool reload, const gchar *_contentType, const gchar *refresh, GTime _lastModified, KWIQPageCache* pageCache) { m_generatedFrameNameId = 0; clearFrameContents(true); WebCoreBridge::openURL(_URL, reload, _contentType, refresh, _lastModified, pageCache); VisitedURLHistory::sharedProvider()->insertVisitedURL(_URL); } /** * call didNotOpenURL(URL) * if user doesn't accept the load (popup-blocker, form submission dialog */ void BridgeImpl::loadURL(const gchar* URL, const gchar* referrer, bool reload, bool onLoadEvent, const gchar* target, NSEvent *event, WebCoreDOM::DOMElement* form, GHashTable* formValues) { WebCoreBridge *targetBridge = this; if (isEmptyString(m_frameName)) assignToString(&m_frameName, target); if (!isEmptyString(target)) targetBridge = findFrameNamed(target); if (targetBridge && targetBridge != this) { targetBridge->loadURL(URL, referrer, reload, onLoadEvent, target, event, form, formValues); return; } if (!URL) URL = ""; if (!targetBridge) { // unknown windows should open in new window // target will have _blank or some custom name if (onLoadEvent) { // FIXME: implement: settings -> block popups didNotOpenURL(URL); } else { targetBridge = mainFrame()->createWindowWithURL(URL, target); if (targetBridge) targetBridge->mainFrame()->showWindow(); return; } } closeURL(); if (createRequest(URL, referrer, reload, HttpRequest::GET)) { provisionalLoadStarted(); emitFrameLoadStarted(); m_activeRequest->execute(); } } void BridgeImpl::postWithURL(const gchar* URL, const gchar *referrer, const gchar* target, GByteArray* data, const gchar* contentType, NSEvent *onLoadEvent, WebCoreDOM::DOMElement *form, GHashTable *formValues) { WebCoreBridge *targetBridge = this; if (!isEmptyString(target)) targetBridge = findFrameNamed(target); if (targetBridge && targetBridge != this) { targetBridge->postWithURL(URL, referrer, target, data,contentType, onLoadEvent, form, formValues); return; } if (!targetBridge) { // unknown windows should open in new window // target will have _blank or some custom name if (onLoadEvent) { // FIXME: implement: settings -> block popups didNotOpenURL(URL); } else { targetBridge = mainFrame()->createWindowWithURL(URL, target); if (targetBridge) targetBridge->mainFrame()->showWindow(); return; } } m_generatedFrameNameId = 0; if (createRequest(URL, referrer, false, HttpRequest::POST)) { m_activeRequest->setPostData(contentType, data); provisionalLoadStarted(); emitFrameLoadStarted(); m_activeRequest->execute(); } } bool BridgeImpl::createRequest(const gchar* URL, const gchar* referrer, const bool reload, const HttpRequest::Method method) { setRequestedURI(URL); gchar *pageURL = 0L; if (!isEmptyString(URL)) { GURI * uri = gnet_uri_new(URL); gnet_uri_set_fragment(uri, 0L); pageURL = gnet_uri_get_string(uri); gnet_uri_delete(uri); } // the page currently viewed shouldn't be in the cache PageCacheEntry* cacheEntry = 0L; if (!isEmptyString(pageURL)) { cacheEntry = m_pageCache.take(pageURL); if (reload) { m_isReloading = true; delete(cacheEntry); cacheEntry = 0; } } if (isEmptyString(pageURL) || strcmp(pageURL,"about:blank")==0) { createKHTMLViewWithGtkWidget(GTK_WIDGET(m_frameWidget), 0, 0); loadEmptyDocumentSynchronously(); g_free(pageURL); return false; } if (cacheEntry) { delete(cacheEntry); // disabled for the moment #if 0 emitFrameLoadStarted(); clearFrameContents(false); openURL(URL, false /*reload*/, "text/html", "", QDateTime(), cacheEntry); emitTitleChanged(cacheEntry->title().utf8()); delete(cacheEntry); installInFrame(GTK_WIDGET (m_frameWidget)); loadURLFinished(false); g_free(pageURL); return false; #endif } if (m_activeRequest) delete(m_activeRequest); if (m_activeListener) delete(m_activeListener); HttpRequestListener *rl = new PageLoadListener(this, pageURL); m_activeListener = new ContentTransposer(rl); WebCoreCookieAdapter * adapter = WebCoreCookieAdapter::sharedAdapter(); m_activeRequest = getHttpFactory().createRequest(m_activeListener, credentials(), pageURL, adapter->cookiesForURL(pageURL), method); if (m_activeRequest) { if (!isEmptyString(referrer)) m_activeRequest->setReferrer(referrer); if (reload) m_activeRequest->setForceReload(true); m_activeRequest->setUserAgent(userAgentForURL(URL)); g_free(pageURL); return true; } else { delete(m_activeListener); m_activeListener = 0; } #ifdef DEBUG g_printerr("%s could not create request for url: %s\n", __PRETTY_FUNCTION__, URL); #endif g_free(pageURL); return false; } WebCoreBridge* BridgeImpl::createWindowWithURL(const gchar* URL, const gchar* name) { assert(URL); assert(name); BridgeImpl* newbridge = createNewRoot(URL); if (!newbridge) { return 0; } if (strcmp(name, "_blank") != 0 && strcmp(name, "_new") != 0) { newbridge->setName(name); } return newbridge; } const gchar* BridgeImpl::userAgentForURL(const gchar* URL) { return engineUserAgentString(); } const gchar* BridgeImpl::engineUserAgentString() { // FIXME: this should be dynamic. return "Mozilla/5.0 (X11; U; Linux i686; en-us) AppleWebKit/146.1 (KHTML, like Gecko)"; } void BridgeImpl::setTitle(const gchar* title) { emitTitleChanged(title); } void BridgeImpl::setStatusText(const gchar* status) { emitSetStatusText(status); } void BridgeImpl::setIconURL(const gchar* URL) { g_warning("NotYetImplemented: %s", __PRETTY_FUNCTION__); } void BridgeImpl::setIconURL(const gchar* URL, const gchar* name) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } WebCoreBridge* BridgeImpl::createChildFrameNamed(const gchar* frameName, const gchar* URL, KHTMLRenderPart *renderPart, bool allowsScrolling, int marginWidth, int marginHeight) { assert(renderPart); assert(frameName); assert(URL); BridgeImpl* newbridge = createChildFrame(); newbridge->didSetName(frameName); // name is aready in name list of the caller. Just set our name newbridge->createKHTMLViewWithGtkWidget(GTK_WIDGET (m_frameWidget), marginWidth, marginHeight); newbridge->setRenderPart(renderPart); newbridge->installInFrame(GTK_WIDGET (newbridge->m_frameWidget)); m_childFrames = g_list_append(m_childFrames, newbridge); if (allowsScrolling == false) { gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (newbridge->m_frameWidget), GTK_POLICY_NEVER, GTK_POLICY_NEVER); } newbridge->loadURL(URL, referrer(), false, false, frameName, 0, 0, 0); return newbridge; } GtkWidget *BridgeImpl::firstResponder() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); return 0; } void BridgeImpl::makeFirstResponder(GtkWidget *view) { if (!gtk_widget_is_focus(view)) { gtk_widget_grab_focus(view); } } WebCoreResourceHandle* BridgeImpl::startLoadingResource(WebCoreResourceLoader *loader, const gchar* URL, GHashTable* headers) { assert(loader); assert(URL); GURI* realURI = 0; if (!realURI) { realURI = gnet_uri_new_relative(m_currentURI, URL); } gchar* realURL = gnet_uri_get_string(realURI); gnet_uri_delete(realURI); ResourceLoadListener* listener = new ResourceLoadListener(this, loader); WebCoreCookieAdapter* adapter = WebCoreCookieAdapter::sharedAdapter(); HttpRequest* req = getHttpFactory().createRequest(listener, credentials(), realURL, adapter->cookiesForURL(realURL), HttpRequest::GET); g_free(realURL); if (req) { req->setUserAgent(userAgentForURL(URL)); req->execute(); return listener->handle(req); } return 0L; } WebCoreResourceHandle* BridgeImpl::startLoadingResource(WebCoreResourceLoader *loader, const gchar* URL, GHashTable* headers, GByteArray* data) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); return 0; } void BridgeImpl::objectLoadedFromCacheWithURL(const gchar* URL, WebCoreResponse* response, unsigned bytes) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } void BridgeImpl::syncLoadResourceWithURL(const gchar* URL, GHashTable* requestHeaders, GByteArray* requestPostData, GByteArray* outData, gchar** outFinalURL, GHashTable* outHeaders, int* outStatusCode) { GURI* realURI = gnet_uri_new_relative(m_currentURI, URL); gchar* realURL = gnet_uri_get_string(realURI); gnet_uri_delete(realURI); // cant be auto allocated due to emulating apple's mem management SynchronousLoader* syncLoader = new SynchronousLoader(URL, outData, outHeaders); ResourceLoadListener* listener = new ResourceLoadListener(this, syncLoader); WebCoreCookieAdapter * adapter = WebCoreCookieAdapter::sharedAdapter(); HttpRequest *req = getHttpFactory().createSynchronizedRequest(listener, credentials(), realURL, adapter->cookiesForURL(realURL), HttpRequest::GET); g_free(realURL); if (req) { req->setUserAgent(userAgentForURL(URL)); req->execute(); if (outFinalURL) *outFinalURL = syncLoader->dupFinalURI(); if (outStatusCode) *outStatusCode = syncLoader->statusCode(); } } bool BridgeImpl::isReloading() { return m_isReloading; } void BridgeImpl::reportClientRedirectToURL(const gchar* URL, double seconds, GTime date, bool lockHistory, bool isJavaScriptFormAction) { m_isRedirecting = true; emitClientRedirectReceived(URL); } void BridgeImpl::reportClientRedirectCancelled(bool cancelWithLoadInProgress) { m_isRedirecting = false; g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); emitClientRedirectCancelled(""); } void BridgeImpl::focusWindow() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } void BridgeImpl::unfocusWindow() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } GtkWidget* BridgeImpl::nextKeyViewOutsideWebFrameViews() { m_unfocusView = true; return gtk_widget_get_parent(GTK_WIDGET(m_frameWidget)); } GtkWidget* BridgeImpl::previousKeyViewOutsideWebFrameViews() { m_unfocusView = true; return gtk_widget_get_parent(GTK_WIDGET(m_frameWidget)); } bool BridgeImpl::defersLoading() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); return false; } void BridgeImpl::setDefersLoading(bool loading) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } void BridgeImpl::saveDocumentState(GList* documentState) { freeGListOfStrings(m_documentState); m_documentState = 0; GList* iter = documentState; while(iter) { m_documentState = g_list_append(m_documentState, g_strdup((gchar*)iter->data)); iter = g_list_next(iter); } } GList* BridgeImpl::documentState() { return m_documentState; } void BridgeImpl::setNeedsReapplyStyles() { m_shouldReapplyStyles = true; } const gchar* BridgeImpl::requestedURLString() { return m_requestedURIString; } const gchar* BridgeImpl::incomingReferrer() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); return ""; } bool BridgeImpl::saveDocumentToPageCache(KWIQPageState *documentInfo) { //FIXME: query title from DOM m_pageCache.insertByURL(m_currentURIString, documentInfo, ""); return true; } int BridgeImpl::getObjectCacheSize() { return 1000; } bool BridgeImpl::frameRequiredForMIMEType(const gchar* MIMEType, const gchar* URL) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); return false; } void BridgeImpl::loadEmptyDocumentSynchronously() { provisionalLoadStarted(); openURL("about:blank", false, "text/html", "", 0/*timeval*/, 0); setEncoding("latin1", true); addData(0, 0); end(); } const gchar* BridgeImpl::MIMETypeForPath(const gchar* path) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); return "text/html"; } void BridgeImpl::handleMouseDragged(NSEvent *event) { g_warning("NotYetImplemented: %s", __PRETTY_FUNCTION__); } void BridgeImpl::handleAutoscrollForMouseDragged(NSEvent *event) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } bool BridgeImpl::mayStartDragWithMouseDragged(NSEvent *event) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); return false; } int BridgeImpl::historyLength() { return history().length(); } void BridgeImpl::goBackOrForward(int distance) { int to = history().pos() + distance; if (to >=0 && to < history().length()) { history().setPos(to); history().lock(); const gchar* url = history().current(); loadURL(url, "", false, // reload: NO false, // onLoadEvent: onLoad "_self", // target: nil 0, // triggeringEvent: nil 0, // form: nil 0); // formValues } } void BridgeImpl::sizeAllocate(GtkWidget *widget, GtkAllocation* allocation) { if (m_oldCanvasSize.x == allocation->x && m_oldCanvasSize.y == allocation->y && m_oldCanvasSize.width == allocation->width && m_oldCanvasSize.height == allocation->height) return; m_oldCanvasSize = *allocation; GtkAdjustment* ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(m_frameWidget)); GtkAdjustment* va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_frameWidget)); va->page_increment = (gdouble) allocation->width; ha->page_increment = (gdouble) allocation->height; forceLayoutAdjustingViewSize(false); sendResizeEvent(); } gboolean BridgeImpl::focus(GtkWidget *widget, GtkDirectionType dir) { GtkWidget *foundWidget = 0; m_unfocusView = false; switch (dir){ case GTK_DIR_TAB_FORWARD: foundWidget = nextKeyView(); break; case GTK_DIR_TAB_BACKWARD: foundWidget = previousKeyView(); break; default: // Dont focus for anything else // stop propagating arrow keys return TRUE; } if (foundWidget && !m_unfocusView) { makeFirstResponder(foundWidget); return TRUE; } return FALSE; } gboolean BridgeImpl::keyPress(GtkWidget* widget, GdkEventKey* event) { bool intercept = interceptKeyEvent(event, false); if (intercept) return TRUE; switch (event->keyval){ case GDK_Left: g_signal_emit_by_name(GTK_SCROLLED_WINDOW(m_frameWidget), "scroll-child", GTK_SCROLL_STEP_LEFT, false); return TRUE; case GDK_Right: g_signal_emit_by_name(GTK_SCROLLED_WINDOW(m_frameWidget), "scroll-child", GTK_SCROLL_STEP_RIGHT, false); return TRUE; case GDK_Up: g_signal_emit_by_name(GTK_SCROLLED_WINDOW(m_frameWidget), "scroll-child", GTK_SCROLL_STEP_UP, true); return TRUE; case GDK_Down: g_signal_emit_by_name(GTK_SCROLLED_WINDOW(m_frameWidget), "scroll-child", GTK_SCROLL_STEP_DOWN, true); return TRUE; case GDK_space: if (event->state & GDK_SHIFT_MASK) g_signal_emit_by_name(GTK_SCROLLED_WINDOW(m_frameWidget), "scroll-child", GTK_SCROLL_PAGE_UP, true); else g_signal_emit_by_name(GTK_SCROLLED_WINDOW(m_frameWidget), "scroll-child", GTK_SCROLL_PAGE_DOWN, true); return TRUE; default: break; } return FALSE; } gboolean BridgeImpl::keyRelease(GtkWidget* widget, GdkEventKey* event) { return keyPress(widget, event); } // notice: if we have GtkLayout inside GtkScrollView, the // widget == GtkLayout, // widget->window == GtkLayout's outer window ("viewport") // event->window == GtkLayout's inner window (big window, global coords) gint BridgeImpl::buttonPress(GtkWidget *widget, GdkEventButton *event) { if (!gtk_widget_is_focus(GTK_WIDGET(m_frameWidget))) gtk_widget_grab_focus(GTK_WIDGET(m_frameWidget)); GdkEventButton viewportEvent = *event; gint x = (gint)event->x, y = (gint)event->y; mapToParentWindow(widget->window, event->window, x, y); viewportEvent.x = (gdouble)x; viewportEvent.y = (gdouble)y; mouseDown((GdkEvent*)&viewportEvent); return TRUE; } gint BridgeImpl::buttonRelease(GtkWidget *widget, GdkEventButton *event) { GdkEventButton viewportEvent = *event; gint x = (gint)event->x, y = (gint)event->y; mapToParentWindow(widget->window, event->window, x, y); viewportEvent.x = (gdouble)x; viewportEvent.y = (gdouble)y; mouseUp((GdkEvent*)&viewportEvent); return TRUE; } gint BridgeImpl::motionNotify(GtkWidget *widget, GdkEventMotion* event) { GdkModifierType state = (GdkModifierType) event->state; gint x = (gint) event->x, y = (gint)event->y; if (event->is_hint) gdk_window_get_pointer(event->window, &x, &y, &state); gint viewportx = x; gint viewporty = y; // hackish workaround because we want coordinates in viewport coordinates, not layout coordinates GdkEventMotion viewportEvent = *event; viewportEvent.state = state; mapToParentWindow(widget->window, event->window, viewportx, viewporty); viewportEvent.x = (gdouble)viewportx; viewportEvent.y = (gdouble)viewporty; mouseMoved(&viewportEvent); WebCoreElementInfo info; memset(&info, 0, sizeof(info)); elementAtPoint(x, y, &info); emitMouseOverChanged(&info); #define FREE_IF_VALID(x) if ((x)) g_free((x)); FREE_IF_VALID(info.linkTitle); FREE_IF_VALID(info.linkLabel); FREE_IF_VALID(info.linkURL); FREE_IF_VALID(info.linkTarget); FREE_IF_VALID(info.imageURL); FREE_IF_VALID(info.imageAltText); #undef FREE_IF_VALID return TRUE; } gint BridgeImpl::expose(GtkWidget *widget, GdkEventExpose *event) { if (m_inExpose) return FALSE; m_inExpose = true; GdkRectangle exposeRect = event->area; if (hasStaticBackground()) { GtkAdjustment* ha = gtk_layout_get_hadjustment(GTK_LAYOUT(m_frameCanvas)); GtkAdjustment* va = gtk_layout_get_vadjustment(GTK_LAYOUT(m_frameCanvas)); GtkAllocation* a = &m_frameCanvas->allocation; fillGdkRectangle(&exposeRect, (int)ha->value, (int)va->value, (int)ha->value + a->width, (int)va->value + a->height); } if (m_shouldReapplyStyles) { m_shouldReapplyStyles = false; reapplyStylesForDeviceType(deviceType()); } GdkRegion* paintRegion = gdk_region_rectangle(&exposeRect); gdk_window_begin_paint_region(event->window, paintRegion); #if _WIN32 Win32Context gc(this, GTK_LAYOUT(m_frameCanvas)->bin_window); #else GdkXftContext gc(this, GTK_LAYOUT(m_frameCanvas)->bin_window); #endif drawRect(&exposeRect, &gc); gdk_window_end_paint(event->window); gdk_region_destroy(paintRegion); m_inExpose = false; return TRUE; } extern "C" { static void _remove_child(GtkWidget* child, gpointer data) { GtkContainer* container = GTK_CONTAINER (data); assert(container); assert(child); gtk_container_remove(container, child); #ifdef DEBUG g_printerr("removed child %x\n", (int) child); #endif } } void BridgeImpl::clearFrameContents(bool createView) { #ifdef DEBUG g_printerr("clear frame contents \n"); #endif gtk_container_foreach(GTK_CONTAINER (m_frameCanvas), _remove_child, GTK_CONTAINER (m_frameCanvas)); #ifdef DEBUG g_printerr("clear frame contents end\n"); #endif if (createView) createKHTMLViewWithGtkWidget(GTK_WIDGET(m_frameWidget), 0,0); } void BridgeImpl::disconnectFrameContents() { m_frameCanvas = 0; } void BridgeImpl::connectFrameContents() { m_frameCanvas.connect("expose_event", ::expose, this); m_frameCanvas.connect("motion_notify_event", ::motion_notify, this); m_frameCanvas.connect("button_press_event", ::button_press, this); m_frameCanvas.connect("button_release_event", ::button_release, this); m_frameCanvas.connect("focus", ::focus, this); m_frameCanvas.connect("focus-in-event", ::focus_inout_event, this); m_frameCanvas.connect("focus-out-event", ::focus_inout_event, this); m_frameCanvas.connect("size_allocate", ::size_allocate, this); m_eventBox.connect("key-press-event", ::key_press_or_release, this); m_eventBox.connect("key-release-event", ::key_press_or_release, this); gtk_widget_hide(GTK_WIDGET (m_frameWidget)); gtk_widget_show_all(GTK_WIDGET (m_frameWidget)); } void BridgeImpl::setHasBorder(bool hasBorder) { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } WebCoreKeyboardUIMode BridgeImpl::keyboardUIMode() { return WebCoreKeyboardUIMode (WebCoreKeyboardAccessFull | WebCoreKeyboardAccessTabsToLinks); }; void BridgeImpl::didSetName(const gchar* name) { assignToString(&m_frameName, name); g_warning("%s %s %s", __PRETTY_FUNCTION__, name,m_frameName); } void BridgeImpl::loadURLFinished(bool hasError) { delete(m_activeRequest); m_activeRequest = 0; end(); m_isReloading = false; history().unlock(); // unlock the history if (!m_isRedirecting) scrollToAnchorWithURL(m_requestedURIString); else m_isRedirecting = false; } GtkWidget* BridgeImpl::widgetForPluginWithURL(const gchar* URL, GList* attributesArray, const gchar* baseURLString, const gchar *MIMEType) { #if 0 OSB::ContentRepresentationFactory *reprf = closestMatchForMIME(mainFrame()->reprForMIME, MIMEType); if (reprf) { OSB::ContentRepresentation *repr = reprf->create(MIMEType.latin1()); return new PluginWidget(reprf, repr); } #endif gchar str[100]; g_snprintf(str, 100, "plugin for mimeType: %s", MIMEType); GtkWidget *b = gtk_label_new(str); return b; } #if 0 const gchar* BridgeImpl::renderTreeString() { return _renderTree_u8 = renderTreeAsExternalRepresentation(); } #endif void BridgeImpl::print() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } void BridgeImpl::issueCutCommand() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); assert(0); } void BridgeImpl::issueCopyCommand() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); assert(0); } void BridgeImpl::issuePasteCommand() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); assert(0); } void BridgeImpl::respondToChangedSelection() { emitSelectionChanged(); } void BridgeImpl::respondToChangedContents() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } /** other methods */ GtkWidget* BridgeImpl::widget() { return GTK_WIDGET(m_eventBox); } void BridgeImpl::saveHistoryItem() { if (!isReloading()) { VisitedURLHistory::sharedProvider()->insertVisitedURL(m_requestedURIString); history().pushNew(m_requestedURIString); } } SimpleHistory& BridgeImpl::history() { return m_history; } void BridgeImpl::setFrameName(const gchar* frameName) { } void BridgeImpl::reapplyStylesForDeviceType(OSB::DeviceType deviceType) { WebCoreDeviceType device = WebCoreDeviceScreen; switch (deviceType) { default: /* Fallthrough to default as "screen" */ case OSB::DeviceScreen: break; case OSB::DeviceHandheld: device = WebCoreDeviceHandheld; break; case OSB::DevicePrinter: device = WebCoreDevicePrinter; break; } WebCoreBridge::reapplyStylesForDeviceType(device); } const gchar* BridgeImpl::overrideMediaTypes() { if (deviceType() == OSB::DeviceHandheld) { return "handheld,screen"; } return 0L; } void BridgeImpl::windowObjectCleared() { g_warning("NotYetImplemented: %s",__PRETTY_FUNCTION__); } bool BridgeImpl::canGoBack() { return history().pos()>0; } bool BridgeImpl::canGoForward() { return history().pos() < (history().length()-1); } void BridgeImpl::goForward() { if (canGoForward()) history().next(); const gchar* url = history().current(); history().lock(); loadURL(url, "", // referer: false, // reload: false, // onLoadEvent: "_self", // target: 0, // triggeringEvent: 0, // form: 0); // formValues: } void BridgeImpl::goBack() { if (canGoBack()) history().prev(); const gchar* url = history().current(); history().lock(); loadURL(url, "", // referer false, // reload: false, // onLoadEvent: "_self", // target: 0, // triggeringEvent: 0, // form: 0); // formValues: } void BridgeImpl::addContentRepresentation(OSB::ContentRepresentationFactory* reprf, const char* mimeType) { } struct ExpiringRect { GTimeVal moment; GdkRectangle rect; }; // ret values -1, 0, 1, if a is less than, equalto, greater than b static gint own_g_time_val_cmp(const GTimeVal* a, const GTimeVal* b) { glong aval, bval; aval = a->tv_sec; bval = b->tv_sec; if (aval == bval) { aval = a->tv_usec; bval = b->tv_usec; } if (aval < bval) return -1; return aval > bval; } extern "C" { static gint expiring_rect_cmp(gconstpointer a, gconstpointer b) { const ExpiringRect *ar; const ExpiringRect *br; ar = static_cast(a); br = static_cast(b); return own_g_time_val_cmp(&ar->moment, &br->moment); } } void BridgeImpl::regionExpiresAt(GTimeVal* moment, GdkRectangle* rect, CGContext* caller) { ExpiringRect *r = g_new(ExpiringRect, 1); r->moment = *moment; r->rect = *rect; m_expiringRects = g_list_insert_sorted(m_expiringRects, r, expiring_rect_cmp); rescheduleExpiringRect(); } void BridgeImpl::rescheduleExpiringRect() { if (!m_expiringRects) { assert(!m_nextExpiringMoment); assert(!m_nextExpiringId); return; } ExpiringRect *first_rect = static_cast(m_expiringRects->data); if (m_nextExpiringMoment && (own_g_time_val_cmp(m_nextExpiringMoment, &first_rect->moment) == 0)) { // no change return; } if (m_nextExpiringId) { assert(m_nextExpiringMoment); g_source_remove(m_nextExpiringId); } GTimeVal now; g_get_current_time(&now); guint timeout = 0; if (own_g_time_val_cmp(&first_rect->moment, &now) >0) { timeout = ((first_rect->moment.tv_sec - now.tv_sec) * 1000) + ((first_rect->moment.tv_usec - now.tv_usec) / 1000); } m_nextExpiringMoment = &first_rect->moment; m_nextExpiringId = g_timeout_add(timeout, (GSourceFunc) ::expiring_rect_timeout, this); } void BridgeImpl::expiringRectTimeout() { assert(m_expiringRects); assert(m_nextExpiringMoment); assert(m_nextExpiringId); GTimeVal now; g_get_current_time(&now); while (m_expiringRects) { ExpiringRect* e_rect = static_cast(m_expiringRects->data); if (own_g_time_val_cmp(&e_rect->moment, &now) == 1) break; // delete first item in list m_expiringRects = g_list_delete_link(m_expiringRects, m_expiringRects); gdk_window_invalidate_rect(GTK_LAYOUT(m_frameCanvas)->bin_window, &e_rect->rect, TRUE); // delete the rectangle g_free(e_rect); } m_nextExpiringMoment = 0; m_nextExpiringId = 0; if (m_expiringRects) rescheduleExpiringRect(); } extern "C" { static void expiring_rects_free(gpointer data, gpointer user_data) { g_free(data); } } void BridgeImpl::clearExpiringRects() { if (m_nextExpiringId) g_source_remove(m_nextExpiringId); if (m_expiringRects) { g_list_foreach(m_expiringRects, expiring_rects_free, this); g_list_free(m_expiringRects); m_expiringRects = 0; } } extern "C" { static gboolean expiring_rect_timeout(gpointer user_data) { BridgeImpl* d = static_cast(user_data); d->expiringRectTimeout(); return FALSE; } } void BridgeImpl::redirection(const gchar* uri) { m_isRedirecting = true; setCurrentURI(uri); emitServerRedirected(m_currentURIString); } void BridgeImpl::setCurrentURI(const gchar* uri) { if (m_currentURI) { gnet_uri_delete(m_currentURI); m_currentURI = 0; g_free(m_currentURIString); m_currentURIString = 0; } m_currentURI = gnet_uri_new(uri); m_currentURIString = gnet_uri_get_string(m_currentURI); } void BridgeImpl::setRequestedURI(const gchar* uri) { if (m_requestedURI) { gnet_uri_delete(m_requestedURI); m_requestedURI = 0; g_free(m_requestedURIString); m_requestedURIString = 0; } m_requestedURI = gnet_uri_new(uri); m_requestedURIString= gnet_uri_get_string(m_requestedURI); } void BridgeImpl::changeSettingsDescendingToChildren(WebCoreSettings* s) { assert(s); initializeSettings(s); GList* iter = g_list_first(m_childFrames); BridgeImpl* child; while (iter) { child = static_cast(iter->data); assert(child); child->changeSettingsDescendingToChildren(s); iter= g_list_next(iter); } } GList* BridgeImpl::childFrames() { return m_childFrames; } extern "C" { static void size_allocate( GtkWidget *widget, GtkAllocation *allocation, gpointer data) { #if DEBUG g_printerr("%s widget:%x, data:%x new_dim:(%d,%d;%d,%d)\n", __PRETTY_FUNCTION__, (int)widget, (int)data, allocation->x, allocation->y, allocation->width, allocation->height); #endif BridgeImpl* self = static_cast(data); assert(self); self->sizeAllocate(widget, allocation); } static int expose(GtkWidget *widget, GdkEventExpose *event, gpointer data) { #if DEBUG g_printerr("%s widget:%x event:%x, data:%x (window %x, x:%d,y:%d,w:%d,h:%d)\n", __PRETTY_FUNCTION__, (int)widget, (int)event, (int)data, (int)event->window, event->area.x, event->area.y, event->area.width, event->area.height); #endif BridgeImpl *bridge = static_cast(data); return bridge->expose(widget, event); } static gint motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer data) { BridgeImpl *self = static_cast(data); return self->motionNotify(widget, event); } static gint button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) { BridgeImpl *self = static_cast(data); return self->buttonPress(widget, event); } static gint button_release(GtkWidget *widget, GdkEventButton *event, gpointer data) { BridgeImpl *self = static_cast(data); return self->buttonRelease(widget, event); } static gboolean focus(GtkWidget *widget, GtkDirectionType dir, gpointer data) { #if DEBUG g_printerr("%s: widget:%x dir:%x data:%x \n", __PRETTY_FUNCTION__, (int)widget, (int)dir, (int)data); #endif return FALSE; } static gboolean focus_inout_event(GtkWidget *widget, GdkEventFocus *event, gpointer data) { #if DEBUG g_printerr("%s: widget:%x event:%x data:%x \n", __PRETTY_FUNCTION__, (int)widget, (int)event, (int)data); #endif return FALSE; } static gboolean key_press_or_release(GtkWidget *widget, GdkEventKey *event, gpointer data) { #if DEBUG g_printerr("%s: widget %x, data:%x, event->keyval %d", __PRETTY_FUNCTION__, (int)widget, (int)data, (int)event->keyval); #endif BridgeImpl* self = static_cast(data); assert(self); return self->keyPress(widget, event); } } static void mapToParentWindow(GdkWindow* parent, GdkWindow* child, int&x, int&y) { int nx, ny; while (child != parent) { gdk_window_get_position (child, &nx, &ny); x += nx; y += ny; child = gdk_window_get_parent (child); assert(child); } } /** Local Variables: c-basic-offset: 4 End: */