diff --git a/ChangeLog b/ChangeLog index 9dd1aa5..a639bec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-03-24 Rodney Dawes + + Reviewed by NOBODY (OOPS!!) + + Add -lXt to webcore_libadd when targetting X11. + + * GNUmakefile.am: + 2008-03-21 Rodney Dawes Reviewed by Holger. diff --git a/GNUmakefile.am b/GNUmakefile.am index 4cdd3db..a472789 100644 --- a/GNUmakefile.am +++ b/GNUmakefile.am @@ -240,6 +240,7 @@ endif if TARGET_X11 global_cppflags += -DXP_UNIX +webcore_libadd += -lXt -lnspr4 endif if !ENABLE_DEBUG diff --git a/WebCore/GNUmakefile.am b/WebCore/GNUmakefile.am index b674ba3..ba5130a 100644 --- a/WebCore/GNUmakefile.am +++ b/WebCore/GNUmakefile.am @@ -901,7 +901,10 @@ webcore_sources += \ WebCore/plugins/PluginStream.cpp \ WebCore/plugins/PluginView.cpp \ WebCore/plugins/npapi.cpp \ + WebCore/plugins/gtk/PluginDataGtk.cpp \ WebCore/plugins/gtk/PluginDatabaseGtk.cpp \ + WebCore/plugins/gtk/PluginPackageGtk.cpp \ + WebCore/plugins/gtk/PluginViewGtk.cpp \ WebCore/rendering/AutoTableLayout.cpp \ WebCore/rendering/bidi.cpp \ WebCore/rendering/break_lines.cpp \ @@ -961,6 +964,11 @@ webcore_sources += \ WebCore/xml/XMLHttpRequest.cpp \ WebCore/xml/XMLSerializer.cpp +if TARGET_X11 +webcore_sources += \ + WebCore/plugins/gtk/gtk2xtbin.c +endif + webkitgtk_headers += \ WebCore/platform/gtk/ClipboardGtk.h \ WebCore/platform/gtk/PasteboardHelper.h diff --git a/WebCore/WebCore.pro b/WebCore/WebCore.pro index 8441abe..acde487 100644 --- a/WebCore/WebCore.pro +++ b/WebCore/WebCore.pro @@ -144,6 +144,7 @@ gtk-port { } x11:plugins { DEFINES += XP_UNIX + LIBS += -lXt } INCLUDEPATH += \ @@ -180,6 +181,7 @@ gtk-port { platform/image-decoders/xbm \ loader/gtk \ page/gtk \ + plugins/gtk \ ../WebKit/gtk \ ../WebKit/gtk/WebCoreSupport \ ../WebKit/gtk/webkit @@ -916,13 +918,35 @@ SOURCES += \ xml/XSLTProcessor.cpp gtk-port { + !plugins { + DEFINES += GTK_DISABLE_PLUGINS=1 + } + HEADERS += \ + plugins/gtk/PluginDatabaseGtk.h \ + plugins/gtk/PluginPackageGtk.h \ + plugins/gtk/PluginViewGtk.h + SOURCES += \ platform/graphics/GlyphPageTreeNode.cpp \ platform/graphics/GlyphWidthMap.cpp \ platform/graphics/FontCache.cpp \ platform/graphics/Font.cpp \ platform/graphics/FontFallbackList.cpp \ - platform/graphics/SimpleFontData.cpp + platform/graphics/SimpleFontData.cpp \ + plugins/gtk/PlugInInfoStoreGtk.cpp \ + plugins/gtk/PluginDatabaseGtk.cpp \ + plugins/gtk/PluginPackageGtk.cpp \ + plugins/gtk/PluginViewGtk.cpp \ + plugins/gtk/npapi.cpp + + x11:plugins { + HEADERS += \ + plugins/gtk/gtk2xtbin.h \ + plugins/gtk/xembed.h + + SOURCES += \ + plugins/gtk/gtk2xtbin.c + } } qt-port { @@ -1035,6 +1059,7 @@ qt-port { } gtk-port { + INCLUDEPATH += ../WebCore/plugins/gtk HEADERS += \ ../WebCore/platform/gtk/ClipboardGtk.h \ ../WebCore/platform/gtk/PasteboardHelper.h \ diff --git a/WebCore/page/gtk/FrameGtk.cpp b/WebCore/page/gtk/FrameGtk.cpp index cfea371..20acad4 100644 --- a/WebCore/page/gtk/FrameGtk.cpp +++ b/WebCore/page/gtk/FrameGtk.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2008 Collabora Ltd. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,15 +31,17 @@ #include "Frame.h" #include "NotImplemented.h" +#include "PluginView.h" +#include "kjs_proxy.h" +#include "runtime_root.h" #include "runtime.h" namespace WebCore { -PassRefPtr Frame::createScriptInstanceForWidget(Widget*) +PassRefPtr Frame::createScriptInstanceForWidget(Widget* widget) { - notImplemented(); - return 0; + return static_cast(widget)->bindingInstance(); } void Frame::clearPlatformScriptObjects() diff --git a/WebCore/platform/gtk/TemporaryLinkStubs.cpp b/WebCore/platform/gtk/TemporaryLinkStubs.cpp index c0dfe0e..2c99823 100644 --- a/WebCore/platform/gtk/TemporaryLinkStubs.cpp +++ b/WebCore/platform/gtk/TemporaryLinkStubs.cpp @@ -33,8 +33,6 @@ #include "FTPDirectoryDocument.h" #include "KURL.h" #include "NotImplemented.h" -#include "PluginPackage.h" -#include "PluginData.h" #include "PluginView.h" #include "SharedBuffer.h" @@ -58,28 +56,7 @@ Vector loadResourceIntoArray(const char* resourceName) /* Completely empty stubs (mostly to allow DRT to run): */ /********************************************************/ -int PluginPackage::compare(const PluginPackage&) const { notImplemented(); return 0; } -bool PluginPackage::fetchInfo() { notImplemented(); return false; } -unsigned PluginPackage::hash() const { notImplemented(); return 0; } -bool PluginPackage::equal(const PluginPackage&, const PluginPackage&) { notImplemented(); return false; } -bool PluginPackage::load() { notImplemented(); return false; } -void PluginView::setNPWindowRect(const IntRect&) { notImplemented(); } -const char* PluginView::userAgent() { notImplemented(); return 0; } -void PluginView::invalidateRect(NPRect*) { notImplemented(); } void PluginView::invalidateRegion(NPRegion) { notImplemented(); } -void PluginView::forceRedraw() { notImplemented(); } -void PluginView::setFocus() { Widget::setFocus(); } -void PluginView::show() { Widget::show(); } -void PluginView::hide() { Widget::hide(); } -void PluginView::paint(GraphicsContext*, const IntRect&) { notImplemented(); } -void PluginView::setParent(ScrollView* view) { Widget::setParent(view); } -void PluginView::attachToWindow() { notImplemented(); } -void PluginView::detachFromWindow() { notImplemented(); } -NPError PluginView::handlePost(const char*, const char*, uint32, const char*, bool, void*, bool, bool) { notImplemented(); return NPERR_GENERIC_ERROR; } -void PluginView::updateWindow() const { notImplemented(); } -void PluginView::handleKeyboardEvent(KeyboardEvent*) { notImplemented(); } -void PluginView::handleMouseEvent(MouseEvent*) { notImplemented(); } -PluginView::~PluginView() {} Color WebCore::focusRingColor() { return 0xFF0000FF; } void WebCore::setFocusRingColorChangeFunction(void (*)()) { } @@ -93,8 +70,5 @@ String KURL::fileSystemPath() const { notImplemented(); return String(); } PassRefPtr SharedBuffer::createWithContentsOfFile(const String&) { notImplemented(); return 0; } -void PluginData::initPlugins() { notImplemented(); } -void PluginData::refresh() { notImplemented(); } - } diff --git a/WebCore/platform/qt/TemporaryLinkStubs.cpp b/WebCore/platform/qt/TemporaryLinkStubs.cpp index 05782b8..0712dd3 100644 --- a/WebCore/platform/qt/TemporaryLinkStubs.cpp +++ b/WebCore/platform/qt/TemporaryLinkStubs.cpp @@ -96,6 +96,7 @@ NPError PluginView::handlePost(const char*, const char*, uint32, const char*, bo void PluginView::updateWindow() const { notImplemented(); } void PluginView::handleKeyboardEvent(KeyboardEvent*) { notImplemented(); } void PluginView::handleMouseEvent(MouseEvent*) { notImplemented(); } +NPError PluginView::getValue (NPNVariable, void*) { notImplemented(); return NPERR_GENERIC_ERROR; } PluginView::~PluginView() {} namespace WebCore { diff --git a/WebCore/plugins/PluginPackage.cpp b/WebCore/plugins/PluginPackage.cpp index 818f661..7a8a7bb 100644 --- a/WebCore/plugins/PluginPackage.cpp +++ b/WebCore/plugins/PluginPackage.cpp @@ -27,16 +27,30 @@ #include "config.h" #include "PluginPackage.h" +#include "CString.h" #include "MIMETypeRegistry.h" +#include "PluginDatabase.h" #include "PluginDebug.h" #include "Timer.h" #include "npruntime_impl.h" +#include #include namespace WebCore { PluginPackage::~PluginPackage() { + // This destructor gets called during refresh() if PluginDatabase's + // PluginSet hash is already populated, as it removes items from + // the hash table. Calling the destructor on a loaded plug-in of + // course would cause a crash, so we check to call unload before we + // ASSERT. + // FIXME: There is probably a better way to fix this. + if (m_loadCount == 0) + unloadWithoutShutdown(); + else + unload(); + ASSERT(!m_isLoaded); } @@ -58,6 +72,30 @@ void PluginPackage::freeLibraryTimerFired(Timer*) m_module = 0; } +int PluginPackage::compare(const PluginPackage& compareTo) const +{ + // Sort plug-ins that allow multiple instances first. + bool AallowsMultipleInstances = !quirks().contains(PluginQuirkDontAllowMultipleInstances); + bool BallowsMultipleInstances = !compareTo.quirks().contains(PluginQuirkDontAllowMultipleInstances); + if (AallowsMultipleInstances != BallowsMultipleInstances) + return AallowsMultipleInstances ? -1 : 1; + + // Sort plug-ins in a preferred path first. + bool AisInPreferredPath = PluginDatabase::isPreferredPluginDirectory(parentDirectory()); + bool BisInPreferredPath = PluginDatabase::isPreferredPluginDirectory(compareTo.parentDirectory()); + if (AisInPreferredPath != BisInPreferredPath) + return AisInPreferredPath ? -1 : 1; + + int diff = strcmp(name().utf8().data(), compareTo.name().utf8().data()); + if (diff) + return diff; + + if (diff = compareFileVersion(compareTo.version())) + return diff; + + return strcmp(parentDirectory().utf8().data(), compareTo.parentDirectory().utf8().data()); +} + PluginPackage::PluginPackage(const String& path, const time_t& lastModified) : m_path(path) , m_moduleVersion(0) diff --git a/WebCore/plugins/PluginView.cpp b/WebCore/plugins/PluginView.cpp index f5553af..4151639 100644 --- a/WebCore/plugins/PluginView.cpp +++ b/WebCore/plugins/PluginView.cpp @@ -393,55 +393,6 @@ void PluginView::status(const char* message) page->chrome()->setStatusbarText(m_parentFrame, String(message)); } -NPError PluginView::getValue(NPNVariable variable, void* value) -{ - if (m_isJavaScriptPaused) - return NPERR_GENERIC_ERROR; - - switch (variable) { -#if ENABLE(NETSCAPE_PLUGIN_API) - case NPNVWindowNPObject: { - NPObject* windowScriptObject = m_parentFrame->windowScriptNPObject(); - - // Return value is expected to be retained, as described here: - if (windowScriptObject) - _NPN_RetainObject(windowScriptObject); - - void** v = (void**)value; - *v = windowScriptObject; - - return NPERR_NO_ERROR; - } - - case NPNVPluginElementNPObject: { - NPObject* pluginScriptObject = 0; - - if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) - pluginScriptObject = static_cast(m_element)->getNPObject(); - - // Return value is expected to be retained, as described here: - if (pluginScriptObject) - _NPN_RetainObject(pluginScriptObject); - - void** v = (void**)value; - *v = pluginScriptObject; - - return NPERR_NO_ERROR; - } -#endif - - case NPNVnetscapeWindow: { - PlatformWidget* w = reinterpret_cast(value); - - *w = containingWindow(); - - return NPERR_NO_ERROR; - } - default: - return NPERR_GENERIC_ERROR; - } -} - NPError PluginView::setValue(NPPVariable variable, void* value) { switch (variable) { diff --git a/WebCore/plugins/PluginView.h b/WebCore/plugins/PluginView.h index 46c77fc..3fac7d9 100644 --- a/WebCore/plugins/PluginView.h +++ b/WebCore/plugins/PluginView.h @@ -221,6 +221,10 @@ namespace WebCore { bool m_attachedToWindow; bool m_haveInitialized; +#if PLATFORM(GTK) + bool m_needsXEmbed; +#endif + #if PLATFORM(WIN) OwnPtr m_messageThrottler; WNDPROC m_pluginWndProc; diff --git a/WebCore/plugins/gtk/PluginDataGtk.cpp b/WebCore/plugins/gtk/PluginDataGtk.cpp new file mode 100644 index 0000000..c3f3f3a --- /dev/null +++ b/WebCore/plugins/gtk/PluginDataGtk.cpp @@ -0,0 +1,72 @@ +/* + Copyright (C) 2008 Trolltech ASA + Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "PluginData.h" + +#include "PluginDatabase.h" +#include "PluginPackage.h" + +namespace WebCore { + +void PluginData::initPlugins() +{ + PluginDatabase *db = PluginDatabase::installedPlugins(); + const Vector &plugins = db->plugins(); + + for (unsigned int i = 0; i < plugins.size(); ++i) { + PluginInfo* info = new PluginInfo; + PluginPackage* package = plugins[i]; + + info->name = package->name(); + info->file = package->fileName(); + info->desc = package->description(); + + const MIMEToDescriptionsMap& mimeToDescriptions = package->mimeToDescriptions(); + MIMEToDescriptionsMap::const_iterator end = mimeToDescriptions.end(); + for (MIMEToDescriptionsMap::const_iterator it = mimeToDescriptions.begin(); it != end; ++it) { + MimeClassInfo* mime = new MimeClassInfo; + info->mimes.append(mime); + + mime->type = it->first; + mime->desc = it->second; + mime->plugin = info; + + Vector extensions = package->mimeToExtensions().get(mime->type); + + for (unsigned i = 0; i < extensions.size(); i++) { + if (i > 0) + mime->suffixes += ","; + + mime->suffixes += extensions[i]; + } + } + + m_plugins.append(info); + } +} + +void PluginData::refresh() +{ + PluginDatabase *db = PluginDatabase::installedPlugins(); + db->refresh(); +} + +}; diff --git a/WebCore/plugins/gtk/PluginDatabaseGtk.cpp b/WebCore/plugins/gtk/PluginDatabaseGtk.cpp index ddc091b..8ff9c5c 100644 --- a/WebCore/plugins/gtk/PluginDatabaseGtk.cpp +++ b/WebCore/plugins/gtk/PluginDatabaseGtk.cpp @@ -29,6 +29,7 @@ #include "CString.h" #include "PluginPackage.h" +#include namespace WebCore { @@ -47,7 +48,7 @@ void PluginDatabase::getPluginPathsInDirectories(HashSet& paths) const if (!g_str_has_suffix(name, "." G_MODULE_SUFFIX)) continue; - gchar* filename = g_build_filename((it->utf8()).data(), name, 0); + gchar* filename = g_build_filename((it->utf8()).data(), name, NULL); paths.add(filename); g_free(filename); } @@ -60,8 +61,10 @@ Vector PluginDatabase::defaultPluginDirectories() Vector directories; gchar* directory; + directory = 0; + #if defined(GDK_WINDOWING_X11) - directory = g_build_filename(g_get_home_dir(), ".mozilla", "plugins", 0); + directory = g_build_filename(g_get_home_dir(), ".mozilla", "plugins", NULL); directories.append(directory); g_free(directory); @@ -75,17 +78,17 @@ Vector PluginDatabase::defaultPluginDirectories() g_strfreev(pluginPaths); } - directory = g_build_filename(G_DIR_SEPARATOR_S "usr", "lib", "browser", "plugins", 0); + directory = g_build_filename(G_DIR_SEPARATOR_S "usr", "lib", "browser", "plugins", NULL); directories.append(directory); g_free(directory); - directory = g_build_filename(G_DIR_SEPARATOR_S "usr", "local", "lib", "mozilla", "plugins", 0); + directory = g_build_filename(G_DIR_SEPARATOR_S "usr", "local", "lib", "mozilla", "plugins", NULL); directories.append(directory); g_free (directory); - directory = g_build_filename(G_DIR_SEPARATOR_S "usr", "lib", "mozilla", "plugins", 0); + directory = g_build_filename(G_DIR_SEPARATOR_S "usr", "lib", "mozilla", "plugins", NULL); directories.append(directory); g_free (directory); #elif defined(GDK_WINDOWING_WIN32) - directory = g_build_filename(g_get_home_dir(), "Application Data", "Mozilla", "plugins", 0); + directory = g_build_filename(g_get_home_dir(), "Application Data", "Mozilla", "plugins", NULL); directories.append(directory); g_free(directory); #endif @@ -95,7 +98,21 @@ Vector PluginDatabase::defaultPluginDirectories() bool PluginDatabase::isPreferredPluginDirectory(const String& directory) { - return false; + gchar* homePath; + bool retval = false; + + homePath = 0; + +#if defined(GDK_WINDOWING_X11) + homePath = g_build_filename(g_get_home_dir(), ".mozilla", "plugins", NULL); +#elif defined(GDK_WINDOWING_WIN32) + homePath = g_build_filename(g_get_home_dir(), "Application Data", "Mozilla", "plugins", NULL); +#endif + + if (homePath) + retval = (strcmp(homePath, (directory.utf8()).data()) == 0); + + return retval; } } diff --git a/WebCore/plugins/gtk/PluginPackageGtk.cpp b/WebCore/plugins/gtk/PluginPackageGtk.cpp new file mode 100644 index 0000000..18f66b6 --- /dev/null +++ b/WebCore/plugins/gtk/PluginPackageGtk.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h" +#include "PluginPackage.h" + +#include "CString.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "npruntime_impl.h" +#include "PluginDebug.h" + +namespace WebCore { + +int PluginPackage::compareFileVersion(const PlatformModuleVersion&) const +{ + notImplemented(); + return 0; +} + +void PluginPackage::determineQuirks(const String& mimeType) +{ + if (MIMETypeRegistry::isJavaAppletMIMEType(mimeType)) { + // Because a single process cannot create multiple VMs, and we cannot reliably unload a + // Java VM, we cannot unload the Java plugin, or we'll lose reference to our only VM + m_quirks.add(PluginQuirkDontUnloadPlugin); + + // Setting the window region to an empty region causes bad scrolling repaint problems + // with the Java plug-in. + m_quirks.add(PluginQuirkDontClipToZeroRectWhenScrolling); + } +} + +bool PluginPackage::fetchInfo() +{ + if (!load()) + return false; + + NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription; + NPP_GetValueProcPtr NPP_GetValue; + + g_module_symbol(m_module, "NP_GetMIMEDescription", (void**)&NP_GetMIMEDescription); + g_module_symbol(m_module, "NP_GetValue", (void**)&NPP_GetValue); + + const gchar* types = NP_GetMIMEDescription(); + gchar** mimeDescs = g_strsplit(types, ";", -1); + for (int i = 0; mimeDescs[i] && mimeDescs[i][0]; i++) { + gchar** mimeData = g_strsplit(mimeDescs[i], ":", 3); + + String description = String::fromUTF8(mimeData[2]); + gchar** extensions = g_strsplit(mimeData[1], ",", -1); + + Vector extVector; + for (int j = 0; extensions[j]; j++) + extVector.append(String::fromUTF8(extensions[j])); + + m_mimeToExtensions.add(mimeData[0], extVector); + m_mimeToDescriptions.add(mimeData[0], description); + + g_strfreev(extensions); + g_strfreev(mimeData); + } + g_strfreev(mimeDescs); + + char* buffer = 0; + NPError err = NPP_GetValue(0, NPPVpluginNameString, &buffer); + if (err == NPERR_NO_ERROR) + m_name = buffer; + + buffer = 0; + err = NPP_GetValue(0, NPPVpluginDescriptionString, &buffer); + if (err == NPERR_NO_ERROR) + m_description = buffer; + + return true; +} + +bool PluginPackage::load() +{ + if (m_isLoaded) { + m_loadCount++; + return true; + } + + m_module = g_module_open((m_path.utf8()).data(), G_MODULE_BIND_LOCAL); + if (!m_module) + return false; + + m_isLoaded = true; + + NP_InitializeFuncPtr NP_Initialize; + NPError npErr; + + g_module_symbol(m_module, "NP_Initialize", (void**)&NP_Initialize); + g_module_symbol(m_module, "NP_Shutdown", (void**)&m_NPP_Shutdown); + + if (!NP_Initialize || !m_NPP_Shutdown) + goto abort; + + memset(&m_pluginFuncs, 0, sizeof(m_pluginFuncs)); + m_pluginFuncs.size = sizeof(m_pluginFuncs); + + m_browserFuncs.size = sizeof (m_browserFuncs); + m_browserFuncs.version = NP_VERSION_MINOR; + m_browserFuncs.geturl = NPN_GetURL; + m_browserFuncs.posturl = NPN_PostURL; + m_browserFuncs.requestread = NPN_RequestRead; + m_browserFuncs.newstream = NPN_NewStream; + m_browserFuncs.write = NPN_Write; + m_browserFuncs.destroystream = NPN_DestroyStream; + m_browserFuncs.status = NPN_Status; + m_browserFuncs.uagent = NPN_UserAgent; + m_browserFuncs.memalloc = NPN_MemAlloc; + m_browserFuncs.memfree = NPN_MemFree; + m_browserFuncs.memflush = NPN_MemFlush; + m_browserFuncs.reloadplugins = NPN_ReloadPlugins; + m_browserFuncs.geturlnotify = NPN_GetURLNotify; + m_browserFuncs.posturlnotify = NPN_PostURLNotify; + m_browserFuncs.getvalue = NPN_GetValue; + m_browserFuncs.setvalue = NPN_SetValue; + m_browserFuncs.invalidaterect = NPN_InvalidateRect; + m_browserFuncs.invalidateregion = NPN_InvalidateRegion; + m_browserFuncs.forceredraw = NPN_ForceRedraw; + m_browserFuncs.getJavaEnv = NPN_GetJavaEnv; + m_browserFuncs.getJavaPeer = NPN_GetJavaPeer; + m_browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState; + m_browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState; + + m_browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue; + m_browserFuncs.getstringidentifier = _NPN_GetStringIdentifier; + m_browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers; + m_browserFuncs.getintidentifier = _NPN_GetIntIdentifier; + m_browserFuncs.identifierisstring = _NPN_IdentifierIsString; + m_browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier; + m_browserFuncs.createobject = _NPN_CreateObject; + m_browserFuncs.retainobject = _NPN_RetainObject; + m_browserFuncs.releaseobject = _NPN_ReleaseObject; + m_browserFuncs.invoke = _NPN_Invoke; + m_browserFuncs.invokeDefault = _NPN_InvokeDefault; + m_browserFuncs.evaluate = _NPN_Evaluate; + m_browserFuncs.getproperty = _NPN_GetProperty; + m_browserFuncs.setproperty = _NPN_SetProperty; + m_browserFuncs.removeproperty = _NPN_RemoveProperty; + m_browserFuncs.hasproperty = _NPN_HasMethod; + m_browserFuncs.hasmethod = _NPN_HasProperty; + m_browserFuncs.setexception = _NPN_SetException; + m_browserFuncs.enumerate = _NPN_Enumerate; + + npErr = NP_Initialize(&m_browserFuncs, &m_pluginFuncs); + if (npErr != NPERR_NO_ERROR) + goto abort; + + m_loadCount++; + return true; + +abort: + unloadWithoutShutdown(); + return false; +} + +unsigned PluginPackage::hash() const +{ + unsigned hashCodes[2] = { + m_path.impl()->hash(), + m_lastModified + }; + + return StringImpl::computeHash(reinterpret_cast(hashCodes), 2 * sizeof(unsigned) / sizeof(UChar)); +} + +bool PluginPackage::equal(const PluginPackage& a, const PluginPackage& b) +{ + return a.m_description == b.m_description; +} + +} diff --git a/WebCore/plugins/gtk/PluginViewGtk.cpp b/WebCore/plugins/gtk/PluginViewGtk.cpp new file mode 100644 index 0000000..fb5eac2 --- /dev/null +++ b/WebCore/plugins/gtk/PluginViewGtk.cpp @@ -0,0 +1,757 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h" +#include "PluginView.h" + +#include "Document.h" +#include "DocumentLoader.h" +#include "Element.h" +#include "EventNames.h" +#include "FrameLoader.h" +#include "FrameLoadRequest.h" +#include "FrameTree.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "HTMLNames.h" +#include "HTMLPlugInElement.h" +#include "KeyboardEvent.h" +#include "MouseEvent.h" +#include "NotImplemented.h" +#include "Page.h" +#include "PlatformMouseEvent.h" +#include "PluginDebug.h" +#include "PluginPackage.h" +#include "RenderLayer.h" +#include "Settings.h" +#include "kjs_binding.h" +#include "kjs_proxy.h" +#include "npruntime_impl.h" +#include "runtime.h" +#include "runtime_root.h" +#include +#include + +#include + +#if defined(GDK_WINDOWING_X11) +#include "gtk2xtbin.h" +#include +#endif +#ifdef GDK_WINDOWING_WIN32 +#include +#endif + +using KJS::ExecState; +using KJS::Interpreter; +using KJS::JSLock; +using KJS::JSObject; +using KJS::JSValue; +using KJS::UString; + +using std::min; + +using namespace WTF; + +namespace WebCore { + +using namespace EventNames; +using namespace HTMLNames; + +void PluginView::updateWindow() const +{ + if (!parent() || !m_isWindowed) + return; + + ASSERT(parent()->isFrameView()); + FrameView* frameView = static_cast(parent()); + + IntRect oldWindowRect = m_windowRect; + IntRect oldClipRect = m_clipRect; + + m_windowRect = IntRect(frameView->contentsToWindow(frameGeometry().location()), frameGeometry().size()); + m_clipRect = windowClipRect(); + m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); + + GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() }; + if (m_window) { + gtk_widget_size_allocate(m_window, &allocation); +#if defined(GDK_WINDOWING_X11) + if (!m_needsXEmbed) { + gtk_xtbin_set_position(GTK_XTBIN(m_window), m_windowRect.x(), m_windowRect.y()); + gtk_xtbin_resize(m_window, m_windowRect.width(), m_windowRect.height()); + } +#endif + } +} + +void PluginView::setFocus() +{ + if (m_window) + gtk_widget_grab_focus(m_window); + + Widget::setFocus(); +} + +void PluginView::show() +{ + m_isVisible = true; + + if (m_attachedToWindow && m_window) + gtk_widget_show(m_window); + + Widget::show(); +} + +void PluginView::hide() +{ + m_isVisible = false; + + if (m_attachedToWindow && m_window) + gtk_widget_hide(m_window); + + Widget::hide(); +} + +void PluginView::paint(GraphicsContext* context, const IntRect& rect) +{ + if (!m_isStarted) { + // Draw the "missing plugin" image + //paintMissingPluginIcon(context, rect); + return; + } + + if (m_isWindowed || context->paintingDisabled()) + return; + + NPEvent npEvent; + /* Need to synthesize Xevents here */ + + m_npWindow.type = NPWindowTypeDrawable; + + ASSERT(parent()->isFrameView()); + + if (m_plugin->pluginFuncs()->event) { + KJS::JSLock::DropAllLocks dropAllLocks; + m_plugin->pluginFuncs()->event(m_instance, &npEvent); + } + + if (m_isWindowed) + setNPWindowRect(frameGeometry()); + + if (m_plugin->pluginFuncs()->event) { + KJS::JSLock::DropAllLocks dropAllLocks; + m_plugin->pluginFuncs()->event(m_instance, &npEvent); + } +} + +void PluginView::handleKeyboardEvent(KeyboardEvent* event) +{ + NPEvent npEvent; + + /* FIXME: Synthesize an XEvent to pass through */ + + KJS::JSLock::DropAllLocks dropAllLocks; + if (!m_plugin->pluginFuncs()->event(m_instance, &npEvent)) + event->setDefaultHandled(); +} + +void PluginView::handleMouseEvent(MouseEvent* event) +{ + NPEvent npEvent; + + if (!m_isWindowed) + return; + + /* FIXME: Synthesize an XEvent to pass through */ + IntPoint p = static_cast(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY())); + + KJS::JSLock::DropAllLocks dropAllLocks; + if (!m_plugin->pluginFuncs()->event(m_instance, &npEvent)) + event->setDefaultHandled(); +} + +void PluginView::setParent(ScrollView* parent) +{ + Widget::setParent(parent); + + if (parent) + init(); + else { + if (!m_window) + return; + } +} + +void PluginView::setNPWindowRect(const IntRect& rect) +{ + if (!m_isStarted || !m_isWindowed) + return; + + if (!parent()) + return; + + IntPoint p = static_cast(parent())->contentsToWindow(rect.location()); + m_npWindow.x = p.x(); + m_npWindow.y = p.y(); + + m_npWindow.width = rect.width(); + m_npWindow.height = rect.height(); + + m_npWindow.clipRect.left = 0; + m_npWindow.clipRect.top = 0; + m_npWindow.clipRect.right = rect.width(); + m_npWindow.clipRect.bottom = rect.height(); + + if (m_plugin->pluginFuncs()->setwindow) { + KJS::JSLock::DropAllLocks dropAllLocks; + m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); + + if (!m_isWindowed) + return; + + ASSERT(m_window); + } +} + +void PluginView::attachToWindow() +{ + if (m_attachedToWindow) + return; + + m_attachedToWindow = true; + if (m_isVisible && m_window) + gtk_widget_show(m_window); +} + +void PluginView::detachFromWindow() +{ + if (!m_attachedToWindow) + return; + + if (m_isVisible && m_window) + gtk_widget_hide(m_window); + m_attachedToWindow = false; +} + +void PluginView::stop() +{ + if (!m_isStarted) + return; + + HashSet > streams = m_streams; + HashSet >::iterator end = streams.end(); + for (HashSet >::iterator it = streams.begin(); it != end; ++it) { + (*it)->stop(); + disconnectStream((*it).get()); + } + + ASSERT(m_streams.isEmpty()); + + m_isStarted = false; + + KJS::JSLock::DropAllLocks dropAllLocks; + + // Destroy the plugin + m_plugin->pluginFuncs()->destroy(m_instance, 0); + + m_instance->pdata = 0; +} + +static void freeStringArray(char** stringArray, int length) +{ + if (!stringArray) + return; + + for (int i = 0; i < length; i++) + fastFree(stringArray[i]); + + fastFree(stringArray); +} + +static KURL makeURL(const KURL& baseURL, const char* relativeURLString) +{ + String urlString = relativeURLString; + + // Strip return characters. + urlString.replace('\n', ""); + urlString.replace('\r', ""); + + return KURL(baseURL, urlString); +} + +static inline bool startsWithBlankLine(const Vector& buffer) +{ + return buffer.size() > 0 && buffer[0] == '\n'; +} + +const char* PluginView::userAgent() +{ + if (m_userAgent.isNull()) + m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8(); + + return m_userAgent.data(); +} + +static inline int locationAfterFirstBlankLine(const Vector& buffer) +{ + const char* bytes = buffer.data(); + unsigned length = buffer.size(); + + for (unsigned i = 0; i < length - 4; i++) { + // Support for Acrobat. It sends "\n\n". + if (bytes[i] == '\n' && bytes[i + 1] == '\n') + return i + 2; + + // Returns the position after 2 CRLF's or 1 CRLF if it is the first line. + if (bytes[i] == '\r' && bytes[i + 1] == '\n') { + i += 2; + if (i == 2) + return i; + else if (bytes[i] == '\n') + // Support for Director. It sends "\r\n\n" (3880387). + return i + 1; + else if (bytes[i] == '\r' && bytes[i + 1] == '\n') + // Support for Flash. It sends "\r\n\r\n" (3758113). + return i + 2; + } + } + + return -1; +} + +static inline const char* findEOL(const char* bytes, unsigned length) +{ + // According to the HTTP specification EOL is defined as + // a CRLF pair. Unfortunately, some servers will use LF + // instead. Worse yet, some servers will use a combination + // of both (e.g.
CRLFLF), so findEOL needs + // to be more forgiving. It will now accept CRLF, LF or + // CR. + // + // It returns NULL if EOLF is not found or it will return + // a pointer to the first terminating character. + for (unsigned i = 0; i < length; i++) { + if (bytes[i] == '\n') + return bytes + i; + if (bytes[i] == '\r') { + // Check to see if spanning buffer bounds + // (CRLF is across reads). If so, wait for + // next read. + if (i + 1 == length) + break; + + return bytes + i; + } + } + + return 0; +} + +static inline String capitalizeRFC822HeaderFieldName(const String& name) +{ + bool capitalizeCharacter = true; + String result; + + for (unsigned i = 0; i < name.length(); i++) { + UChar c; + + if (capitalizeCharacter && name[i] >= 'a' && name[i] <= 'z') + c = toASCIIUpper(name[i]); + else if (!capitalizeCharacter && name[i] >= 'A' && name[i] <= 'Z') + c = toASCIILower(name[i]); + else + c = name[i]; + + if (name[i] == '-') + capitalizeCharacter = true; + else + capitalizeCharacter = false; + + result.append(c); + } + + return result; +} + +static inline HTTPHeaderMap parseRFC822HeaderFields(const Vector& buffer, unsigned length) +{ + const char* bytes = buffer.data(); + const char* eol; + String lastKey; + HTTPHeaderMap headerFields; + + // Loop ove rlines until we're past the header, or we can't find any more end-of-lines + while ((eol = findEOL(bytes, length))) { + const char* line = bytes; + int lineLength = eol - bytes; + + // Move bytes to the character after the terminator as returned by findEOL. + bytes = eol + 1; + if ((*eol == '\r') && (*bytes == '\n')) + bytes++; // Safe since findEOL won't return a spanning CRLF. + + length -= (bytes - line); + if (lineLength == 0) + // Blank line; we're at the end of the header + break; + else if (*line == ' ' || *line == '\t') { + // Continuation of the previous header + if (lastKey.isNull()) { + // malformed header; ignore it and continue + continue; + } else { + // Merge the continuation of the previous header + String currentValue = headerFields.get(lastKey); + String newValue(line, lineLength); + + headerFields.set(lastKey, currentValue + newValue); + } + } else { + // Brand new header + const char* colon; + for (colon = line; *colon != ':' && colon != eol; colon++) { + // empty loop + } + if (colon == eol) + // malformed header; ignore it and continue + continue; + else { + lastKey = capitalizeRFC822HeaderFieldName(String(line, colon - line)); + String value; + + for (colon++; colon != eol; colon++) { + if (*colon != ' ' && *colon != '\t') + break; + } + if (colon == eol) + value = ""; + else + value = String(colon, eol - colon); + + String oldValue = headerFields.get(lastKey); + if (!oldValue.isNull()) { + String tmp = oldValue; + tmp += ", "; + tmp += value; + value = tmp; + } + + headerFields.set(lastKey, value); + } + } + } + + return headerFields; +} + +NPError PluginView::handlePost(const char* url, const char* target, uint32 len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders) +{ + if (!url || !len || !buf) + return NPERR_INVALID_PARAM; + + FrameLoadRequest frameLoadRequest; + + HTTPHeaderMap headerFields; + Vector buffer; + + if (file) { + String filename(buf, len); + + if (filename.startsWith("file:///")) + filename = filename.substring(8); + + // Get file info + if (!g_file_test ((filename.utf8()).data(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) + return NPERR_FILE_NOT_FOUND; + + //FIXME - read the file data into buffer + FILE* fileHandle = fopen((filename.utf8()).data(), "r"); + + if (fileHandle == 0) + return NPERR_FILE_NOT_FOUND; + + //buffer.resize(); + + int bytesRead = fread(buffer.data(), 1, 0, fileHandle); + + fclose(fileHandle); + + if (bytesRead <= 0) + return NPERR_FILE_NOT_FOUND; + + return NPERR_NO_ERROR; + } else { + buffer.resize(len); + memcpy(buffer.data(), buf, len); + } + + const char* postData = buffer.data(); + int postDataLength = buffer.size(); + + if (allowHeaders) { + if (startsWithBlankLine(buffer)) { + postData++; + postDataLength--; + } else { + int location = locationAfterFirstBlankLine(buffer); + if (location != -1) { + // If the blank line is somewhere in the middle of the buffer, everything before is the header + headerFields = parseRFC822HeaderFields(buffer, location); + unsigned dataLength = buffer.size() - location; + + // Sometimes plugins like to set Content-Length themselves when they post, + // but WebFoundation does not like that. So we will remove the header + // and instead truncate the data to the requested length. + String contentLength = headerFields.get("Content-Length"); + + if (!contentLength.isNull()) + dataLength = min(contentLength.toInt(), (int)dataLength); + headerFields.remove("Content-Length"); + + postData += location; + postDataLength = dataLength; + } + } + } + + frameLoadRequest.resourceRequest().setHTTPMethod("POST"); + frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url)); + frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields); + frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(postData, postDataLength)); + frameLoadRequest.setFrameName(target); + + return load(frameLoadRequest, sendNotification, notifyData); +} + +NPError PluginView::getValue(NPNVariable variable, void* value) +{ + switch (variable) { +#if defined(GDK_WINDOWING_X11) + case NPNVxtAppContext: { + if (!m_needsXEmbed) { + *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(m_window)->xtclient.xtdisplay); + + return NPERR_NO_ERROR; + } else + return NPERR_GENERIC_ERROR; + } +#endif + + case NPNVToolkit: { +#if PLATFORM(GTK) + *((uint32 *)value) = 2; +#else + *((uint32 *)value) = 0; +#endif + return NPERR_NO_ERROR; + } + + case NPNVSupportsXEmbedBool: { +#if defined(GDK_WINDOWING_X11) + *((uint32 *)value) = true; +#else + *((uint32 *)value) = false; +#endif + return NPERR_NO_ERROR; + } + +#if ENABLE(NETSCAPE_PLUGIN_API) + case NPNVWindowNPObject: { + if (m_isJavaScriptPaused) + return NPERR_GENERIC_ERROR; + + NPObject* windowScriptObject = m_parentFrame->windowScriptNPObject(); + + // Return value is expected to be retained, as described here: + if (windowScriptObject) + _NPN_RetainObject(windowScriptObject); + + void** v = (void**)value; + *v = windowScriptObject; + + return NPERR_NO_ERROR; + } + + case NPNVPluginElementNPObject: { + if (m_isJavaScriptPaused) + return NPERR_GENERIC_ERROR; + + NPObject* pluginScriptObject = 0; + + if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) + pluginScriptObject = static_cast(m_element)->getNPObject(); + + // Return value is expected to be retained, as described here: + if (pluginScriptObject) + _NPN_RetainObject(pluginScriptObject); + + void** v = (void**)value; + *v = pluginScriptObject; + + return NPERR_NO_ERROR; + } +#endif + + case NPNVnetscapeWindow: { + void* w = reinterpret_cast(value); + +#ifdef GDK_WINDOWING_X11 + *((XID *)w) = GDK_WINDOW_XWINDOW(containingWindow()->window); +#endif +#ifdef GDK_WINDOWING_WIN32 + *((HWND *)w) = GDK_WINDOWING_HWND(containingWindow()->window); +#endif + return NPERR_NO_ERROR; + } + default: + return NPERR_GENERIC_ERROR; + } +} + +void PluginView::invalidateRect(NPRect* rect) +{ + if (!rect) { + invalidate(); + return; + } + + IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); + Widget::invalidateRect(r); +} + +void PluginView::forceRedraw() +{ + if (m_isWindowed) + gtk_widget_queue_draw(m_window); + else + gtk_widget_queue_draw(containingWindow()); +} + +PluginView::~PluginView() +{ + stop(); + + deleteAllValues(m_requests); + + freeStringArray(m_paramNames, m_paramCount); + freeStringArray(m_paramValues, m_paramCount); + + m_parentFrame->cleanupScriptObjectsForPlugin(this); + + if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin))) + m_plugin->unload(); +} + +void PluginView::init() +{ + if (m_haveInitialized) + return; + m_haveInitialized = true; + + if (!m_plugin) { + ASSERT(m_status == PluginStatusCanNotFindPlugin); + return; + } + + if (!m_plugin->load()) { + m_plugin = 0; + m_status = PluginStatusCanNotLoadPlugin; + return; + } + + if (!start()) { + m_status = PluginStatusCanNotLoadPlugin; + return; + } + + if (m_plugin->pluginFuncs()->getvalue) + m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); + +#if defined(GDK_WINDOWING_X11) + if (m_needsXEmbed) { + m_window = gtk_socket_new(); + gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->containingWindow()), m_window); + setGtkWidget(m_window); + } else if (m_isWindowed) { + m_window = gtk_xtbin_new(m_parentFrame->view()->containingWindow()->window, 0); + setGtkWidget(m_window); + } +#else + m_window = gtk_socket_new(); + gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->containingWindow()), m_window); + setGtkWidget(m_window); +#endif + show (); + + if (m_isWindowed) { +#if defined(GDK_WINDOWING_X11) + NPSetWindowCallbackStruct ws; + + ws.type = 0; + + if (m_needsXEmbed) { + ws.display = GDK_WINDOW_XDISPLAY(m_window->window); + ws.visual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(GDK_DRAWABLE(m_window->window))); + ws.depth = gdk_drawable_get_visual(GDK_DRAWABLE(m_window->window))->depth; + ws.colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(GDK_DRAWABLE(m_window->window))); + } else { + ws.display = GTK_XTBIN(m_window)->xtdisplay; + ws.visual = GTK_XTBIN(m_window)->xtclient.xtvisual; + ws.depth = GTK_XTBIN(m_window)->xtclient.xtdepth; + ws.colormap = GTK_XTBIN(m_window)->xtclient.xtcolormap; + + XFlush (ws.display); + } + + m_npWindow.ws_info = &ws; +#endif + } + + if (m_isWindowed) { + m_npWindow.type = NPWindowTypeWindow; +#if defined(GDK_WINDOWING_X11) + if (m_needsXEmbed) + m_npWindow.window = (void*)GDK_WINDOW_XWINDOW(m_window->window); + else + m_npWindow.window = (void*)GTK_XTBIN(m_window)->xtwindow; +#elif defined(GDK_WINDOWING_WIN32) + m_npWindow.window = (void*)GDK_WINDOW_HWND(m_window->window); +#endif + } else { + m_npWindow.type = NPWindowTypeDrawable; + m_npWindow.window = 0; + } + + if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) + setNPWindowRect(frameGeometry()); + + m_status = PluginStatusLoadedSuccessfully; +} + +} // namespace WebCore diff --git a/WebCore/plugins/gtk/gtk2xtbin.c b/WebCore/plugins/gtk/gtk2xtbin.c new file mode 100644 index 0000000..8a9eb20 --- /dev/null +++ b/WebCore/plugins/gtk/gtk2xtbin.c @@ -0,0 +1,940 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:expandtab:shiftwidth=2:tabstop=2: */ + +/* ***** 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 the Gtk2XtBin Widget Implementation. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +/* + * The GtkXtBin widget allows for Xt toolkit code to be used + * inside a GTK application. + */ + +#undef GTK_DISABLE_DEPRECATED + +#include "xembed.h" +#include "gtk2xtbin.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Xlib/Xt stuff */ +#include +#include +#include +#include +#include + +/* uncomment this if you want debugging information about widget + creation and destruction */ +#undef DEBUG_XTBIN + +#define XTBIN_MAX_EVENTS 30 + +static void gtk_xtbin_class_init (GtkXtBinClass *klass); +static void gtk_xtbin_init (GtkXtBin *xtbin); +static void gtk_xtbin_realize (GtkWidget *widget); +static void gtk_xtbin_unrealize (GtkWidget *widget); +static void gtk_xtbin_destroy (GtkObject *object); +static void gtk_xtbin_shutdown (GtkObject *object); + +/* Xt aware XEmbed */ +static void xt_client_init (XtClient * xtclient, + Visual *xtvisual, + Colormap xtcolormap, + int xtdepth); +static void xt_client_create (XtClient * xtclient, + Window embeder, + int height, + int width ); +static void xt_client_unrealize (XtClient* xtclient); +static void xt_client_destroy (XtClient* xtclient); +static void xt_client_set_info (Widget xtplug, + unsigned long flags); +static void xt_client_event_handler (Widget w, + XtPointer client_data, + XEvent *event); +static void xt_client_handle_xembed_message (Widget w, + XtPointer client_data, + XEvent *event); +static void xt_client_focus_listener (Widget w, + XtPointer user_data, + XEvent *event); +static void xt_add_focus_listener( Widget w, XtPointer user_data ); +static void xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data); +static void xt_remove_focus_listener(Widget w, XtPointer user_data); +static void send_xembed_message (XtClient *xtclient, + long message, + long detail, + long data1, + long data2, + long time); +static int error_handler (Display *display, + XErrorEvent *error); +/* For error trap of XEmbed */ +static void trap_errors(void); +static int untrap_error(void); +static int (*old_error_handler) (Display *, XErrorEvent *); +static int trapped_error_code = 0; + +static GtkWidgetClass *parent_class = NULL; + +static Display *xtdisplay = NULL; +static String *fallback = NULL; +static gboolean xt_is_initialized = FALSE; +static gint num_widgets = 0; + +static GPollFD xt_event_poll_fd; +static gint xt_polling_timer_id = 0; +static guint tag = 0; + +static gboolean +xt_event_prepare (GSource* source_data, + gint *timeout) +{ + int mask; + + GDK_THREADS_ENTER(); + mask = XPending(xtdisplay); + GDK_THREADS_LEAVE(); + + return (gboolean)mask; +} + +static gboolean +xt_event_check (GSource* source_data) +{ + GDK_THREADS_ENTER (); + + if (xt_event_poll_fd.revents & G_IO_IN) { + int mask; + mask = XPending(xtdisplay); + GDK_THREADS_LEAVE (); + return (gboolean)mask; + } + + GDK_THREADS_LEAVE (); + return FALSE; +} + +static gboolean +xt_event_dispatch (GSource* source_data, + GSourceFunc call_back, + gpointer user_data) +{ + XEvent event; + XtAppContext ac; + int i = 0; + + ac = XtDisplayToApplicationContext(xtdisplay); + + GDK_THREADS_ENTER (); + + /* Process only real X traffic here. We only look for data on the + * pipe, limit it to XTBIN_MAX_EVENTS and only call + * XtAppProcessEvent so that it will look for X events. There's no + * timer processing here since we already have a timer callback that + * does it. */ + for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) { + XtAppProcessEvent(ac, XtIMXEvent); + } + + GDK_THREADS_LEAVE (); + + return TRUE; +} + +static GSourceFuncs xt_event_funcs = { + xt_event_prepare, + xt_event_check, + xt_event_dispatch, + g_free, + (GSourceFunc)NULL, + (GSourceDummyMarshal)NULL +}; + +static gboolean +xt_event_polling_timer_callback(gpointer user_data) +{ + Display * display; + XtAppContext ac; + int eventsToProcess = 20; + + display = (Display *)user_data; + ac = XtDisplayToApplicationContext(display); + + /* We need to process many Xt events here. If we just process + one event we might starve one or more Xt consumers. On the other hand + this could hang the whole app if Xt events come pouring in. So process + up to 20 Xt events right now and save the rest for later. This is a hack, + but it oughta work. We *really* should have out of process plugins. + */ + while (eventsToProcess-- && XtAppPending(ac)) + XtAppProcessEvent(ac, XtIMAll); + return TRUE; +} + +GtkType +gtk_xtbin_get_type (void) +{ + static GtkType xtbin_type = 0; + + if (!xtbin_type) { + static const GtkTypeInfo xtbin_info = + { + "GtkXtBin", + sizeof (GtkXtBin), + sizeof (GtkXtBinClass), + (GtkClassInitFunc) gtk_xtbin_class_init, + (GtkObjectInitFunc) gtk_xtbin_init, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL + }; + xtbin_type = gtk_type_unique (GTK_TYPE_SOCKET, &xtbin_info); + } + return xtbin_type; +} + +static void +gtk_xtbin_class_init (GtkXtBinClass *klass) +{ + GtkWidgetClass *widget_class; + GtkObjectClass *object_class; + + parent_class = gtk_type_class (GTK_TYPE_SOCKET); + + widget_class = GTK_WIDGET_CLASS (klass); + widget_class->realize = gtk_xtbin_realize; + widget_class->unrealize = gtk_xtbin_unrealize; + + object_class = GTK_OBJECT_CLASS (klass); + object_class->destroy = gtk_xtbin_destroy; +} + +static void +gtk_xtbin_init (GtkXtBin *xtbin) +{ + xtbin->xtdisplay = NULL; + xtbin->parent_window = NULL; + xtbin->xtwindow = 0; + xtbin->x = 0; + xtbin->y = 0; +} + +static void +gtk_xtbin_realize (GtkWidget *widget) +{ + GtkXtBin *xtbin; + GtkAllocation allocation = { 0, 0, 200, 200 }; + gint x, y, w, h, d; /* geometry of window */ + +#ifdef DEBUG_XTBIN + printf("gtk_xtbin_realize()\n"); +#endif + + g_return_if_fail (GTK_IS_XTBIN (widget)); + + xtbin = GTK_XTBIN (widget); + + /* caculate the allocation before realize */ + gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d); + allocation.width = w; + allocation.height = h; + gtk_widget_size_allocate (widget, &allocation); + +#ifdef DEBUG_XTBIN + printf("initial allocation %d %d %d %d\n", x, y, w, h); +#endif + + xtbin->width = widget->allocation.width; + xtbin->height = widget->allocation.height; + + /* use GtkSocket's realize */ + (*GTK_WIDGET_CLASS(parent_class)->realize)(widget); + + /* create the Xt client widget */ + xt_client_create(&(xtbin->xtclient), + gtk_socket_get_id(GTK_SOCKET(xtbin)), + xtbin->height, + xtbin->width); + xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget); + + gdk_flush(); + + /* now that we have created the xt client, add it to the socket. */ + gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow); +} + + + +GtkWidget* +gtk_xtbin_new (GdkWindow *parent_window, String * f) +{ + GtkXtBin *xtbin; + gpointer user_data; + + assert(parent_window != NULL); + xtbin = gtk_type_new (GTK_TYPE_XTBIN); + + if (!xtbin) + return (GtkWidget*)NULL; + + if (f) + fallback = f; + + /* Initialize the Xt toolkit */ + xtbin->parent_window = parent_window; + + xt_client_init(&(xtbin->xtclient), + GDK_VISUAL_XVISUAL(gdk_rgb_get_visual()), + GDK_COLORMAP_XCOLORMAP(gdk_rgb_get_colormap()), + gdk_rgb_get_visual()->depth); + + if (!xtbin->xtclient.xtdisplay) { + /* If XtOpenDisplay failed, we can't go any further. + * Bail out. + */ +#ifdef DEBUG_XTBIN + printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n"); +#endif + g_free (xtbin); + return (GtkWidget *)NULL; + } + + /* If this is the first running widget, hook this display into the + mainloop */ + if (0 == num_widgets) { + int cnumber; + /* + * hook Xt event loop into the glib event loop. + */ + + /* the assumption is that gtk_init has already been called */ + GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource)); + if (!gs) { + return NULL; + } + + g_source_set_priority(gs, GDK_PRIORITY_EVENTS); + g_source_set_can_recurse(gs, TRUE); + tag = g_source_attach(gs, (GMainContext*)NULL); +#ifdef VMS + cnumber = XConnectionNumber(xtdisplay); +#else + cnumber = ConnectionNumber(xtdisplay); +#endif + xt_event_poll_fd.fd = cnumber; + xt_event_poll_fd.events = G_IO_IN; + xt_event_poll_fd.revents = 0; /* hmm... is this correct? */ + + g_main_context_add_poll ((GMainContext*)NULL, + &xt_event_poll_fd, + G_PRIORITY_LOW); + /* add a timer so that we can poll and process Xt timers */ + xt_polling_timer_id = + gtk_timeout_add(25, + (GtkFunction)xt_event_polling_timer_callback, + xtdisplay); + } + + /* Bump up our usage count */ + num_widgets++; + + /* Build the hierachy */ + xtbin->xtdisplay = xtbin->xtclient.xtdisplay; + gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window); + gdk_window_get_user_data(xtbin->parent_window, &user_data); + if (user_data) + gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin)); + + return GTK_WIDGET (xtbin); +} + +void +gtk_xtbin_set_position (GtkXtBin *xtbin, + gint x, + gint y) +{ + xtbin->x = x; + xtbin->y = y; + + if (GTK_WIDGET_REALIZED (xtbin)) + gdk_window_move (GTK_WIDGET (xtbin)->window, x, y); +} + +void +gtk_xtbin_resize (GtkWidget *widget, + gint width, + gint height) +{ + Arg args[2]; + GtkXtBin *xtbin = GTK_XTBIN (widget); + GtkAllocation allocation; + +#ifdef DEBUG_XTBIN + printf("gtk_xtbin_resize %p %d %d\n", (void *)widget, width, height); +#endif + + xtbin->height = height; + xtbin->width = width; + + // Avoid BadValue errors in XtSetValues + if (height <= 0 || width <=0) { + height = 1; + width = 1; + } + XtSetArg(args[0], XtNheight, height); + XtSetArg(args[1], XtNwidth, width); + XtSetValues(xtbin->xtclient.top_widget, args, 2); + + /* we need to send a size allocate so the socket knows about the + size changes */ + allocation.x = xtbin->x; + allocation.y = xtbin->y; + allocation.width = xtbin->width; + allocation.height = xtbin->height; + + gtk_widget_size_allocate(widget, &allocation); +} + +static void +gtk_xtbin_unrealize (GtkWidget *object) +{ + GtkXtBin *xtbin; + GtkWidget *widget; + +#ifdef DEBUG_XTBIN + printf("gtk_xtbin_unrealize()\n"); +#endif + + /* gtk_object_destroy() will already hold a refcount on object + */ + xtbin = GTK_XTBIN(object); + widget = GTK_WIDGET(object); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); + if (GTK_WIDGET_REALIZED (widget)) { + xt_client_unrealize(&(xtbin->xtclient)); + } + + (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget); +} + +static void +gtk_xtbin_destroy (GtkObject *object) +{ + GtkXtBin *xtbin; + +#ifdef DEBUG_XTBIN + printf("gtk_xtbin_destroy()\n"); +#endif + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_XTBIN (object)); + + xtbin = GTK_XTBIN (object); + + if(xtbin->xtwindow) { + /* remove the event handler */ + xt_client_destroy(&(xtbin->xtclient)); + xtbin->xtwindow = 0; + + num_widgets--; /* reduce our usage count */ + + /* If this is the last running widget, remove the Xt display + connection from the mainloop */ + if (0 == num_widgets) { +#ifdef DEBUG_XTBIN + printf("removing the Xt connection from the main loop\n"); +#endif + g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd); + g_source_remove(tag); + + gtk_timeout_remove(xt_polling_timer_id); + xt_polling_timer_id = 0; + } + } + + GTK_OBJECT_CLASS(parent_class)->destroy(object); +} + +/* +* Following is the implementation of Xt XEmbedded for client side +*/ + +/* Initial Xt plugin */ +static void +xt_client_init( XtClient * xtclient, + Visual *xtvisual, + Colormap xtcolormap, + int xtdepth) +{ + XtAppContext app_context; + char *mArgv[1]; + int mArgc = 0; + + /* + * Initialize Xt stuff + */ + xtclient->top_widget = NULL; + xtclient->child_widget = NULL; + xtclient->xtdisplay = NULL; + xtclient->xtvisual = NULL; + xtclient->xtcolormap = 0; + xtclient->xtdepth = 0; + + if (!xt_is_initialized) { +#ifdef DEBUG_XTBIN + printf("starting up Xt stuff\n"); +#endif + XtToolkitInitialize(); + app_context = XtCreateApplicationContext(); + if (fallback) + XtAppSetFallbackResources(app_context, fallback); + + xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL, + "Wrapper", NULL, 0, &mArgc, mArgv); + if (xtdisplay) + xt_is_initialized = TRUE; + } + xtclient->xtdisplay = xtdisplay; + xtclient->xtvisual = xtvisual; + xtclient->xtcolormap = xtcolormap; + xtclient->xtdepth = xtdepth; +} + +/* Create the Xt client widgets +* */ +static void +xt_client_create ( XtClient* xtclient , + Window embedderid, + int height, + int width ) +{ + int n; + Arg args[6]; + Widget child_widget; + Widget top_widget; + +#ifdef DEBUG_XTBIN + printf("xt_client_create() \n"); +#endif + top_widget = XtAppCreateShell("drawingArea", "Wrapper", + applicationShellWidgetClass, + xtclient->xtdisplay, + NULL, 0); + xtclient->top_widget = top_widget; + + /* set size of Xt window */ + n = 0; + XtSetArg(args[n], XtNheight, height);n++; + XtSetArg(args[n], XtNwidth, width);n++; + XtSetValues(top_widget, args, n); + + child_widget = XtVaCreateWidget("form", + compositeWidgetClass, + top_widget, NULL); + + n = 0; + XtSetArg(args[n], XtNheight, height);n++; + XtSetArg(args[n], XtNwidth, width);n++; + XtSetArg(args[n], XtNvisual, xtclient->xtvisual ); n++; + XtSetArg(args[n], XtNdepth, xtclient->xtdepth ); n++; + XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap ); n++; + XtSetArg(args[n], XtNborderWidth, 0); n++; + XtSetValues(child_widget, args, n); + + XSync(xtclient->xtdisplay, FALSE); + xtclient->oldwindow = top_widget->core.window; + top_widget->core.window = embedderid; + + /* this little trick seems to finish initializing the widget */ +#if XlibSpecificationRelease >= 6 + XtRegisterDrawable(xtclient->xtdisplay, + embedderid, + top_widget); +#else + _XtRegisterWindow( embedderid, + top_widget); +#endif + XtRealizeWidget(child_widget); + + /* listen to all Xt events */ + XSelectInput(xtclient->xtdisplay, + XtWindow(top_widget), + 0x0FFFFF); + xt_client_set_info (child_widget, 0); + + XtManageChild(child_widget); + xtclient->child_widget = child_widget; + + /* set the event handler */ + XtAddEventHandler(child_widget, + 0x0FFFFF & ~ResizeRedirectMask, + TRUE, + (XtEventHandler)xt_client_event_handler, xtclient); + XtAddEventHandler(child_widget, + SubstructureNotifyMask | ButtonReleaseMask, + TRUE, + (XtEventHandler)xt_client_focus_listener, + xtclient); + XSync(xtclient->xtdisplay, FALSE); +} + +static void +xt_client_unrealize ( XtClient* xtclient ) +{ +#if XlibSpecificationRelease >= 6 + XtUnregisterDrawable(xtclient->xtdisplay, + xtclient->top_widget->core.window); +#else + _XtUnregisterWindow(xtclient->top_widget->core.window, + xtclient->top_widget); +#endif + + /* flush the queue before we returning origin top_widget->core.window + or we can get X error since the window is gone */ + XSync(xtclient->xtdisplay, False); + + xtclient->top_widget->core.window = xtclient->oldwindow; + XtUnrealizeWidget(xtclient->top_widget); +} + +static void +xt_client_destroy (XtClient* xtclient) +{ + if(xtclient->top_widget) { + XtRemoveEventHandler(xtclient->child_widget, 0x0FFFFF, TRUE, + (XtEventHandler)xt_client_event_handler, xtclient); + XtDestroyWidget(xtclient->top_widget); + xtclient->top_widget = NULL; + } +} + +static void +xt_client_set_info (Widget xtplug, unsigned long flags) +{ + unsigned long buffer[2]; + + Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False); + + buffer[1] = 0; /* Protocol version */ + buffer[1] = flags; + + XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug), + infoAtom, infoAtom, 32, + PropModeReplace, + (unsigned char *)buffer, 2); +} + +static void +xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event) +{ + XtClient *xtplug = (XtClient*)client_data; + switch (event->xclient.data.l[1]) + { + case XEMBED_EMBEDDED_NOTIFY: + break; + case XEMBED_WINDOW_ACTIVATE: +#ifdef DEBUG_XTBIN + printf("Xt client get XEMBED_WINDOW_ACTIVATE\n"); +#endif + break; + case XEMBED_WINDOW_DEACTIVATE: +#ifdef DEBUG_XTBIN + printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n"); +#endif + break; + case XEMBED_MODALITY_ON: +#ifdef DEBUG_XTBIN + printf("Xt client get XEMBED_MODALITY_ON\n"); +#endif + break; + case XEMBED_MODALITY_OFF: +#ifdef DEBUG_XTBIN + printf("Xt client get XEMBED_MODALITY_OFF\n"); +#endif + break; + case XEMBED_FOCUS_IN: + case XEMBED_FOCUS_OUT: + { + XEvent xevent; + memset(&xevent, 0, sizeof(xevent)); + + if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) { +#ifdef DEBUG_XTBIN + printf("XTEMBED got focus in\n"); +#endif + xevent.xfocus.type = FocusIn; + } + else { +#ifdef DEBUG_XTBIN + printf("XTEMBED got focus out\n"); +#endif + xevent.xfocus.type = FocusOut; + } + + xevent.xfocus.window = XtWindow(xtplug->child_widget); + xevent.xfocus.display = XtDisplay(xtplug->child_widget); + XSendEvent(XtDisplay(xtplug->child_widget), + xevent.xfocus.window, + False, NoEventMask, + &xevent ); + XSync( XtDisplay(xtplug->child_widget), False); + } + break; + default: + break; + } /* End of XEmbed Message */ +} + +static void +xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event) +{ + XtClient *xtplug = (XtClient*)client_data; + + switch(event->type) + { + case ClientMessage: + /* Handle xembed message */ + if (event->xclient.message_type== + XInternAtom (XtDisplay(xtplug->child_widget), + "_XEMBED", False)) { + xt_client_handle_xembed_message(w, client_data, event); + } + break; + case ReparentNotify: + break; + case MappingNotify: + xt_client_set_info (w, XEMBED_MAPPED); + break; + case UnmapNotify: + xt_client_set_info (w, 0); + break; + case FocusIn: + send_xembed_message ( xtplug, + XEMBED_REQUEST_FOCUS, 0, 0, 0, 0); + break; + case FocusOut: + break; + case KeyPress: +#ifdef DEBUG_XTBIN + printf("Key Press Got!\n"); +#endif + break; + default: + break; + } /* End of switch(event->type) */ +} + +static void +send_xembed_message (XtClient *xtclient, + long message, + long detail, + long data1, + long data2, + long time) +{ + XEvent xevent; + Window w=XtWindow(xtclient->top_widget); + Display* dpy=xtclient->xtdisplay; + int errorcode; + + memset(&xevent,0,sizeof(xevent)); + xevent.xclient.window = w; + xevent.xclient.type = ClientMessage; + xevent.xclient.message_type = XInternAtom(dpy,"_XEMBED",False); + xevent.xclient.format = 32; + xevent.xclient.data.l[0] = time; + xevent.xclient.data.l[1] = message; + xevent.xclient.data.l[2] = detail; + xevent.xclient.data.l[3] = data1; + xevent.xclient.data.l[4] = data2; + + trap_errors (); + XSendEvent (dpy, w, False, NoEventMask, &xevent); + XSync (dpy,False); + + if((errorcode = untrap_error())) { +#ifdef DEBUG_XTBIN + printf("send_xembed_message error(%d)!!!\n",errorcode); +#endif + } +} + +static int +error_handler(Display *display, XErrorEvent *error) +{ + trapped_error_code = error->error_code; + return 0; +} + +static void +trap_errors(void) +{ + trapped_error_code =0; + old_error_handler = XSetErrorHandler(error_handler); +} + +static int +untrap_error(void) +{ + XSetErrorHandler(old_error_handler); + if(trapped_error_code) { +#ifdef DEBUG_XTBIN + printf("Get X Window Error = %d\n", trapped_error_code); +#endif + } + return trapped_error_code; +} + +static void +xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event) +{ + Display *dpy = XtDisplay(w); + XtClient *xtclient = user_data; + Window win = XtWindow(w); + + switch(event->type) + { + case CreateNotify: + if(event->xcreatewindow.parent == win) { + Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window); + if (child) + xt_add_focus_listener_tree(child, user_data); + } + break; + case DestroyNotify: + xt_remove_focus_listener( w, user_data); + break; + case ReparentNotify: + if(event->xreparent.parent == win) { + /* I am the new parent */ + Widget child=XtWindowToWidget(dpy, event->xreparent.window); + if (child) + xt_add_focus_listener_tree( child, user_data); + } + else if(event->xreparent.window == win) { + /* I am the new child */ + } + else { + /* I am the old parent */ + } + break; + case ButtonRelease: +#if 0 + XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time); +#endif + send_xembed_message ( xtclient, + XEMBED_REQUEST_FOCUS, 0, 0, 0, 0); + break; + default: + break; + } /* End of switch(event->type) */ +} + +static void +xt_add_focus_listener( Widget w, XtPointer user_data) +{ + XWindowAttributes attr; + long eventmask; + XtClient *xtclient = user_data; + int errorcode; + + trap_errors (); + XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attr); + eventmask = attr.your_event_mask | SubstructureNotifyMask | ButtonReleaseMask; + XSelectInput(XtDisplay(w), + XtWindow(w), + eventmask); + + XtAddEventHandler(w, + SubstructureNotifyMask | ButtonReleaseMask, + TRUE, + (XtEventHandler)xt_client_focus_listener, + xtclient); + untrap_error(); +} + +static void +xt_remove_focus_listener(Widget w, XtPointer user_data) +{ + int errorcode; + + trap_errors (); + XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, TRUE, + (XtEventHandler)xt_client_focus_listener, user_data); + + untrap_error(); +} + +static void +xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data) +{ + Window win = XtWindow(treeroot); + Window *children; + Window root, parent; + Display *dpy = XtDisplay(treeroot); + unsigned int i, nchildren; + + /* ensure we don't add more than once */ + xt_remove_focus_listener( treeroot, user_data); + xt_add_focus_listener( treeroot, user_data); + trap_errors(); + if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) { + untrap_error(); + return; + } + + if(untrap_error()) + return; + + for(i=0; i +#include +#include +#include +#ifdef MOZILLA_CLIENT +#include "nscore.h" +#ifdef _IMPL_GTKXTBIN_API +#define GTKXTBIN_API(type) NS_EXPORT_(type) +#else +#define GTKXTBIN_API(type) NS_IMPORT_(type) +#endif +#else +#define GTKXTBIN_API(type) type +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _GtkXtBin GtkXtBin; +typedef struct _GtkXtBinClass GtkXtBinClass; + +#define GTK_TYPE_XTBIN (gtk_xtbin_get_type ()) +#define GTK_XTBIN(obj) (GTK_CHECK_CAST ((obj), \ + GTK_TYPE_XTBIN, GtkXtBin)) +#define GTK_XTBIN_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), \ + GTK_TYPE_XTBIN, GtkXtBinClass)) +#define GTK_IS_XTBIN(obj) (GTK_CHECK_TYPE ((obj), \ + GTK_TYPE_XTBIN)) +#define GTK_IS_XTBIN_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), \ + GTK_TYPE_XTBIN)) +typedef struct _XtClient XtClient; + +struct _XtClient { + Display *xtdisplay; + Widget top_widget; /* The toplevel widget */ + Widget child_widget; /* The embedded widget */ + Visual *xtvisual; + int xtdepth; + Colormap xtcolormap; + Window oldwindow; +}; + +struct _GtkXtBin +{ + GtkSocket gsocket; + GdkWindow *parent_window; + Display *xtdisplay; /* Xt Toolkit Display */ + + Window xtwindow; /* Xt Toolkit XWindow */ + gint x, y; + gint width, height; + XtClient xtclient; /* Xt Client for XEmbed */ +}; + +struct _GtkXtBinClass +{ + GtkSocketClass widget_class; +}; + +GTKXTBIN_API(GtkType) gtk_xtbin_get_type (void); +GTKXTBIN_API(GtkWidget *) gtk_xtbin_new (GdkWindow *parent_window, String *f); +GTKXTBIN_API(void) gtk_xtbin_set_position (GtkXtBin *xtbin, + gint x, + gint y); +GTKXTBIN_API(void) gtk_xtbin_resize (GtkWidget *widget, + gint width, + gint height); + +typedef struct _XtTMRec { + XtTranslations translations; /* private to Translation Manager */ + XtBoundActions proc_table; /* procedure bindings for actions */ + struct _XtStateRec *current_state; /* Translation Manager state ptr */ + unsigned long lastEventTime; +} XtTMRec, *XtTM; + +typedef struct _CorePart { + Widget self; /* pointer to widget itself */ + WidgetClass widget_class; /* pointer to Widget's ClassRec */ + Widget parent; /* parent widget */ + XrmName xrm_name; /* widget resource name quarkified */ + Boolean being_destroyed; /* marked for destroy */ + XtCallbackList destroy_callbacks; /* who to call when widget destroyed */ + XtPointer constraints; /* constraint record */ + Position x, y; /* window position */ + Dimension width, height; /* window dimensions */ + Dimension border_width; /* window border width */ + Boolean managed; /* is widget geometry managed? */ + Boolean sensitive; /* is widget sensitive to user events*/ + Boolean ancestor_sensitive; /* are all ancestors sensitive? */ + XtEventTable event_table; /* private to event dispatcher */ + XtTMRec tm; /* translation management */ + XtTranslations accelerators; /* accelerator translations */ + Pixel border_pixel; /* window border pixel */ + Pixmap border_pixmap; /* window border pixmap or NULL */ + WidgetList popup_list; /* list of popups */ + Cardinal num_popups; /* how many popups */ + String name; /* widget resource name */ + Screen *screen; /* window's screen */ + Colormap colormap; /* colormap */ + Window window; /* window ID */ + Cardinal depth; /* number of planes in window */ + Pixel background_pixel; /* window background pixel */ + Pixmap background_pixmap; /* window background pixmap or NULL */ + Boolean visible; /* is window mapped and not occluded?*/ + Boolean mapped_when_managed;/* map window if it's managed? */ +} CorePart; + +typedef struct _WidgetRec { + CorePart core; + } WidgetRec, CoreRec; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __GTK_XTBIN_H__ */ diff --git a/WebCore/plugins/gtk/xembed.h b/WebCore/plugins/gtk/xembed.h new file mode 100644 index 0000000..dd3978f --- /dev/null +++ b/WebCore/plugins/gtk/xembed.h @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:expandtab:shiftwidth=2:tabstop=2: */ + +/* ***** 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 the XEMBED Declaration. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +/* XEMBED messages */ +#define XEMBED_EMBEDDED_NOTIFY 0 +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_WINDOW_DEACTIVATE 2 +#define XEMBED_REQUEST_FOCUS 3 +#define XEMBED_FOCUS_IN 4 +#define XEMBED_FOCUS_OUT 5 +#define XEMBED_FOCUS_NEXT 6 +#define XEMBED_FOCUS_PREV 7 +#define XEMBED_GRAB_KEY 8 +#define XEMBED_UNGRAB_KEY 9 +#define XEMBED_MODALITY_ON 10 +#define XEMBED_MODALITY_OFF 11 + +/* Non standard messages*/ +#define XEMBED_GTK_GRAB_KEY 108 +#define XEMBED_GTK_UNGRAB_KEY 109 + +/* Details for XEMBED_FOCUS_IN: */ +#define XEMBED_FOCUS_CURRENT 0 +#define XEMBED_FOCUS_FIRST 1 +#define XEMBED_FOCUS_LAST 2 + +/* Flags for _XEMBED_INFO */ +#define XEMBED_MAPPED (1 << 0) +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:expandtab:shiftwidth=2:tabstop=2: */ + +/* ***** 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 the XEMBED Declaration. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +/* XEMBED messages */ +#define XEMBED_EMBEDDED_NOTIFY 0 +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_WINDOW_DEACTIVATE 2 +#define XEMBED_REQUEST_FOCUS 3 +#define XEMBED_FOCUS_IN 4 +#define XEMBED_FOCUS_OUT 5 +#define XEMBED_FOCUS_NEXT 6 +#define XEMBED_FOCUS_PREV 7 +#define XEMBED_GRAB_KEY 8 +#define XEMBED_UNGRAB_KEY 9 +#define XEMBED_MODALITY_ON 10 +#define XEMBED_MODALITY_OFF 11 + +/* Non standard messages*/ +#define XEMBED_GTK_GRAB_KEY 108 +#define XEMBED_GTK_UNGRAB_KEY 109 + +/* Details for XEMBED_FOCUS_IN: */ +#define XEMBED_FOCUS_CURRENT 0 +#define XEMBED_FOCUS_FIRST 1 +#define XEMBED_FOCUS_LAST 2 + +/* Flags for _XEMBED_INFO */ +#define XEMBED_MAPPED (1 << 0) diff --git a/WebCore/plugins/win/PluginViewWin.cpp b/WebCore/plugins/win/PluginViewWin.cpp index 1e1ffbc..25cff44 100644 --- a/WebCore/plugins/win/PluginViewWin.cpp +++ b/WebCore/plugins/win/PluginViewWin.cpp @@ -858,6 +858,58 @@ NPError PluginView::handlePost(const char* url, const char* target, uint32 len, return load(frameLoadRequest, sendNotification, notifyData); } +NPError PluginView::getValue(NPNVariable variable, void* value) +{ + switch (variable) { +#if ENABLE(NETSCAPE_PLUGIN_API) + case NPNVWindowNPObject: { + if (m_isJavaScriptPaused) + return NPERR_GENERIC_ERROR; + + NPObject* windowScriptObject = m_parentFrame->windowScriptNPObject(); + + // Return value is expected to be retained, as described here: + if (windowScriptObject) + _NPN_RetainObject(windowScriptObject); + + void** v = (void**)value; + *v = windowScriptObject; + + return NPERR_NO_ERROR; + } + + case NPNVPluginElementNPObject: { + if (m_isJavaScriptPaused) + return NPERR_GENERIC_ERROR; + + NPObject* pluginScriptObject = 0; + + if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) + pluginScriptObject = static_cast(m_element)->getNPObject(); + + // Return value is expected to be retained, as described here: + if (pluginScriptObject) + _NPN_RetainObject(pluginScriptObject); + + void** v = (void**)value; + *v = pluginScriptObject; + + return NPERR_NO_ERROR; + } +#endif + + case NPNVnetscapeWindow: { + PlatformWidget* w = reinterpret_cast(value); + + *w = containingWindow(); + + return NPERR_NO_ERROR; + } + default: + return NPERR_GENERIC_ERROR; + } +} + void PluginView::invalidateRect(NPRect* rect) { if (!rect) { diff --git a/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp b/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp index dda3810..5b729bc 100644 --- a/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp +++ b/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2007 Alp Toker * Copyright (C) 2007, 2008 Holger Hans Peter Freyther * Copyright (C) 2007 Christian Dywan + * Copyright (C) 2008 Collabora Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -56,6 +57,7 @@ namespace WebKit { FrameLoaderClient::FrameLoaderClient(WebKitWebFrame* frame) : m_frame(frame) + , m_pluginView(0) , m_userAgent("") { ASSERT(m_frame); @@ -161,9 +163,30 @@ void FrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction policyFunctio void FrameLoaderClient::committedLoad(DocumentLoader* loader, const char* data, int length) { - FrameLoader *fl = loader->frameLoader(); - fl->setEncoding(m_response.textEncodingName(), false); - fl->addData(data, length); + const String& textEncoding = loader->response().textEncodingName(); + + if (!m_pluginView) { + ASSERT(loader->frame()); + // Setting the encoding on the frame loader is our way to get work done that is normally done + // when the first bit of data is received, even for the case of a document with no data (like about:blank). + String encoding = loader->overrideEncoding(); + bool userChosen = !encoding.isNull(); + if (!userChosen) + encoding = loader->response().textEncodingName(); + + FrameLoader* frameLoader = loader->frameLoader(); + frameLoader->setEncoding(encoding, userChosen); + if (data) + frameLoader->addData(data, length); + } + + if (m_pluginView) { + if (!m_hasSentResponseToPlugin) { + m_pluginView->didReceiveResponse(loader->response()); + m_hasSentResponseToPlugin = true; + } + m_pluginView->didReceiveData(data, length); + } } void FrameLoaderClient::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) @@ -259,9 +282,13 @@ void FrameLoaderClient::dispatchDecidePolicyForNavigationAction(FramePolicyFunct (core(m_frame)->loader()->*policyFunction)(PolicyUse); } -Widget* FrameLoaderClient::createPlugin(const IntSize&, Element*, const KURL&, const Vector&, const Vector&, const String&, bool) +Widget* FrameLoaderClient::createPlugin(const IntSize& pluginSize, Element* element, const KURL& url, const Vector& paramNames, const Vector& paramValues, const String& mimeType, bool loadManually) { - notImplemented(); + PluginView* pluginView = PluginView::create(core(m_frame), pluginSize, element, url, paramNames, paramValues, mimeType, loadManually); + + if (pluginView->status() == PluginStatusLoadedSuccessfully) + return pluginView; + return 0; } @@ -302,8 +329,7 @@ PassRefPtr FrameLoaderClient::createFrame(const KURL& url, const String& void FrameLoaderClient::redirectDataToPlugin(Widget* pluginWidget) { - notImplemented(); - return; + m_pluginView = static_cast(pluginWidget); } Widget* FrameLoaderClient::createJavaAppletWidget(const IntSize&, Element*, const KURL& baseURL, @@ -599,14 +625,14 @@ String FrameLoaderClient::generatedMIMETypeForURLScheme(const String&) const void FrameLoaderClient::finishedLoading(DocumentLoader* documentLoader) { - ASSERT(documentLoader->frame()); - // Setting the encoding on the frame loader is our way to get work done that is normally done - // when the first bit of data is received, even for the case of a document with no data (like about:blank). - String encoding = documentLoader->overrideEncoding(); - bool userChosen = !encoding.isNull(); - if (encoding.isNull()) - encoding = documentLoader->response().textEncodingName(); - documentLoader->frameLoader()->setEncoding(encoding, userChosen); + + if (!m_pluginView) + committedLoad(documentLoader, 0, 0); + else { + m_pluginView->didFinishLoading(); + m_pluginView = 0; + m_hasSentResponseToPlugin = false; + } } @@ -723,9 +749,13 @@ void FrameLoaderClient::dispatchUnableToImplementPolicy(const ResourceError&) notImplemented(); } -void FrameLoaderClient::setMainDocumentError(DocumentLoader*, const ResourceError&) +void FrameLoaderClient::setMainDocumentError(DocumentLoader*, const ResourceError& error) { - notImplemented(); + if (m_pluginView) { + m_pluginView->didFail(error); + m_pluginView = 0; + m_hasSentResponseToPlugin = false; + } } void FrameLoaderClient::startDownload(const ResourceRequest&) diff --git a/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h b/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h index 1157e30..c5da1b1 100644 --- a/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h +++ b/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 Zack Rusin * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Collabora, Ltd. All rights reserved. * * All rights reserved. * @@ -32,6 +33,8 @@ #include "FrameLoaderClient.h" #include "ResourceResponse.h" +#include "PluginView.h" + typedef struct _WebKitWebFrame WebKitWebFrame; namespace WebKit { @@ -170,6 +173,10 @@ namespace WebKit { WebKitWebFrame* m_frame; WebCore::ResourceResponse m_response; WebCore::String m_userAgent; + + // Plugin view to redirect data to + WebCore::PluginView* m_pluginView; + bool m_hasSentResponseToPlugin; }; } diff --git a/WebKitTools/Scripts/webkitdirs.pm b/WebKitTools/Scripts/webkitdirs.pm index cd2fefb..ad852a1 100644 --- a/WebKitTools/Scripts/webkitdirs.pm +++ b/WebKitTools/Scripts/webkitdirs.pm @@ -1,4 +1,5 @@ # Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. +# Copyright (C) 2007 Collabora, Ltd. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -55,6 +56,7 @@ my $currentSVNRevision; my $osXVersion; my $isQt; my $isGtk; +my $enableGtkPlugins; my $isWx; # Variables for Win32 support @@ -494,6 +496,23 @@ sub determineIsGtk() } } +sub enableGtkPlugins() +{ + determineEnableGtkPlugins(); + return $enableGtkPlugins; +} + +sub determineEnableGtkPlugins() +{ + return if defined($enableGtkPlugins); + + if (checkArgv("--disable-gtk-plugins")) { + $enableGtkPlugins = 0; + } else { + $enableGtkPlugins = 1; + } +} + sub isWx() { determineIsWx(); @@ -865,6 +884,7 @@ sub buildGtkProject($$@) if (useQmake()) { my @buildArgs = ("CONFIG+=gtk-port", "CONFIG-=qt"); + push @buildArgs, "CONFIG+=plugins" if enableGtkPlugins(); return buildQMakeProject($clean, @buildArgs); } else { return buildAutotoolsProject($clean, @buildArgs);