summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/plugins/gtk
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/plugins/gtk
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/plugins/gtk')
-rw-r--r--Source/WebCore/plugins/gtk/PluginDataGtk.cpp65
-rw-r--r--Source/WebCore/plugins/gtk/PluginPackageGtk.cpp176
-rw-r--r--Source/WebCore/plugins/gtk/PluginViewGtk.cpp901
-rw-r--r--Source/WebCore/plugins/gtk/gtk2xtbin.c966
-rw-r--r--Source/WebCore/plugins/gtk/gtk2xtbin.h158
-rw-r--r--Source/WebCore/plugins/gtk/xembed.h64
6 files changed, 2330 insertions, 0 deletions
diff --git a/Source/WebCore/plugins/gtk/PluginDataGtk.cpp b/Source/WebCore/plugins/gtk/PluginDataGtk.cpp
new file mode 100644
index 0000000..705bf9a
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/PluginDataGtk.cpp
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ 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 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"
+#include <stdio.h>
+namespace WebCore {
+
+void PluginData::initPlugins(const Page*)
+{
+ PluginDatabase *db = PluginDatabase::installedPlugins();
+ const Vector<PluginPackage*> &plugins = db->plugins();
+
+ for (unsigned int i = 0; i < plugins.size(); ++i) {
+ PluginInfo info;
+ 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;
+
+ mime.type = it->first;
+ mime.desc = it->second;
+ mime.extensions = package->mimeToExtensions().get(mime.type);
+
+ info.mimes.append(mime);
+ }
+
+ m_plugins.append(info);
+ }
+}
+
+void PluginData::refresh()
+{
+ PluginDatabase *db = PluginDatabase::installedPlugins();
+ db->refresh();
+}
+
+};
diff --git a/Source/WebCore/plugins/gtk/PluginPackageGtk.cpp b/Source/WebCore/plugins/gtk/PluginPackageGtk.cpp
new file mode 100644
index 0000000..a702296
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/PluginPackageGtk.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2008 Novell Inc. 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 <gio/gio.h>
+#include <stdio.h>
+
+#include "GOwnPtr.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "npruntime_impl.h"
+#include "PluginDebug.h"
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+bool PluginPackage::fetchInfo()
+{
+#if defined(XP_UNIX)
+ if (!load())
+ return false;
+
+ NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription = 0;
+ NPP_GetValueProcPtr NPP_GetValue = 0;
+
+ g_module_symbol(m_module, "NP_GetMIMEDescription", (void**)&NP_GetMIMEDescription);
+ g_module_symbol(m_module, "NP_GetValue", (void**)&NPP_GetValue);
+
+ if (!NP_GetMIMEDescription || !NPP_GetValue)
+ return false;
+
+ 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;
+ determineModuleVersionFromDescription();
+ }
+
+ const gchar* types = NP_GetMIMEDescription();
+ if (!types)
+ return true;
+
+ gchar** mimeDescs = g_strsplit(types, ";", -1);
+ for (int i = 0; mimeDescs[i] && mimeDescs[i][0]; i++) {
+ GOwnPtr<char> mime(g_utf8_strdown(mimeDescs[i], -1));
+ gchar** mimeData = g_strsplit(mime.get(), ":", 3);
+ if (g_strv_length(mimeData) < 3) {
+ g_strfreev(mimeData);
+ continue;
+ }
+
+ String description = String::fromUTF8(mimeData[2]);
+ gchar** extensions = g_strsplit(mimeData[1], ",", -1);
+
+ Vector<String> extVector;
+ for (int j = 0; extensions[j]; j++)
+ extVector.append(String::fromUTF8(extensions[j]));
+
+ determineQuirks(mimeData[0]);
+ m_mimeToExtensions.add(mimeData[0], extVector);
+ m_mimeToDescriptions.add(mimeData[0], description);
+
+ g_strfreev(extensions);
+ g_strfreev(mimeData);
+ }
+ g_strfreev(mimeDescs);
+
+ return true;
+#else
+ notImplemented();
+ return false;
+#endif
+}
+
+bool PluginPackage::load()
+{
+ if (m_isLoaded) {
+ m_loadCount++;
+ return true;
+ }
+
+ GOwnPtr<gchar> finalPath(g_strdup(m_path.utf8().data()));
+ while (g_file_test(finalPath.get(), G_FILE_TEST_IS_SYMLINK)) {
+ GOwnPtr<GFile> file(g_file_new_for_path(finalPath.get()));
+ GOwnPtr<GFile> dir(g_file_get_parent(file.get()));
+ GOwnPtr<gchar> linkPath(g_file_read_link(finalPath.get(), 0));
+ GOwnPtr<GFile> resolvedFile(g_file_resolve_relative_path(dir.get(), linkPath.get()));
+ finalPath.set(g_file_get_path(resolvedFile.get()));
+ }
+
+ // No joke. If there is a netscape component in the path, go back
+ // to the symlink, as flash breaks otherwise.
+ // See http://src.chromium.org/viewvc/chrome/trunk/src/webkit/glue/plugins/plugin_list_posix.cc
+ GOwnPtr<gchar> baseName(g_path_get_basename(finalPath.get()));
+ if (!g_strcmp0(baseName.get(), "libflashplayer.so")
+ && g_strstr_len(finalPath.get(), -1, "/netscape/"))
+ finalPath.set(g_strdup(m_path.utf8().data()));
+
+ m_module = g_module_open(finalPath.get(), G_MODULE_BIND_LOCAL);
+
+ if (!m_module) {
+ LOG(Plugins,"Module Load Failed :%s, Error:%s\n", (m_path.utf8()).data(), g_module_error());
+ return false;
+ }
+
+ m_isLoaded = true;
+
+ NP_InitializeFuncPtr NP_Initialize = 0;
+ m_NPP_Shutdown = 0;
+
+ 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);
+
+ initializeBrowserFuncs();
+
+#if defined(XP_UNIX)
+ npErr = NP_Initialize(&m_browserFuncs, &m_pluginFuncs);
+#else
+ npErr = NP_Initialize(&m_browserFuncs);
+#endif
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+
+ m_loadCount++;
+ return true;
+
+abort:
+ unloadWithoutShutdown();
+ return false;
+}
+
+uint16_t PluginPackage::NPVersion() const
+{
+ return NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL;
+}
+}
diff --git a/Source/WebCore/plugins/gtk/PluginViewGtk.cpp b/Source/WebCore/plugins/gtk/PluginViewGtk.cpp
new file mode 100644
index 0000000..ec855a2
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/PluginViewGtk.cpp
@@ -0,0 +1,901 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2009, 2010 Kakai, Inc. <brian@kakai.com>
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * 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 "Bridge.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "FocusController.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameTree.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "HostWindow.h"
+#include "Image.h"
+#include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformMouseEvent.h"
+#include "PluginDebug.h"
+#include "PluginMainThreadScheduler.h"
+#include "PluginPackage.h"
+#include "RenderLayer.h"
+#include "Settings.h"
+#include "JSDOMBinding.h"
+#include "ScriptController.h"
+#include "npruntime_impl.h"
+#include "runtime_root.h"
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+
+#ifdef GTK_API_VERSION_2
+#include <gdkconfig.h>
+#endif
+#include <gtk/gtk.h>
+
+#if defined(XP_UNIX)
+#include "RefPtrCairo.h"
+#include "gtk2xtbin.h"
+#define Bool int // this got undefined somewhere
+#define Status int // ditto
+#include <X11/extensions/Xrender.h>
+#include <cairo/cairo-xlib.h>
+#include <gdk/gdkx.h>
+#elif defined(GDK_WINDOWING_WIN32)
+#include "PluginMessageThrottlerWin.h"
+#include <gdk/gdkwin32.h>
+#endif
+
+using JSC::ExecState;
+using JSC::Interpreter;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::UString;
+
+using std::min;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+bool PluginView::dispatchNPEvent(NPEvent& event)
+{
+ // sanity check
+ if (!m_plugin->pluginFuncs()->event)
+ return false;
+
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+
+ bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event);
+
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ return accepted;
+}
+
+#if defined(XP_UNIX)
+static Window getRootWindow(Frame* parentFrame)
+{
+ GtkWidget* parentWidget = parentFrame->view()->hostWindow()->platformPageClient();
+ GdkScreen* gscreen = gtk_widget_get_screen(parentWidget);
+ return GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(gscreen));
+}
+#endif
+
+void PluginView::updatePluginWidget()
+{
+ if (!parent())
+ return;
+
+ ASSERT(parent()->isFrameView());
+ FrameView* frameView = static_cast<FrameView*>(parent());
+
+ IntRect oldWindowRect = m_windowRect;
+ IntRect oldClipRect = m_clipRect;
+
+ m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
+ m_clipRect = windowClipRect();
+ m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
+
+ if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
+ return;
+
+#if defined(XP_UNIX)
+ if (!m_isWindowed) {
+ Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ if (m_drawable)
+ XFreePixmap(display, m_drawable);
+
+ m_drawable = XCreatePixmap(display, getRootWindow(m_parentFrame.get()),
+ m_windowRect.width(), m_windowRect.height(),
+ ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth);
+ XSync(display, false); // make sure that the server knows about the Drawable
+ }
+#endif
+
+ setNPWindowIfNeeded();
+}
+
+void PluginView::setFocus(bool focused)
+{
+ ASSERT(platformPluginWidget() == platformWidget());
+ Widget::setFocus(focused);
+}
+
+void PluginView::show()
+{
+ ASSERT(platformPluginWidget() == platformWidget());
+ Widget::show();
+}
+
+void PluginView::hide()
+{
+ ASSERT(platformPluginWidget() == platformWidget());
+ Widget::hide();
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_isStarted) {
+ paintMissingPluginIcon(context, rect);
+ return;
+ }
+
+ if (context->paintingDisabled())
+ return;
+
+ setNPWindowIfNeeded();
+
+ if (m_isWindowed)
+ return;
+
+#if defined(XP_UNIX)
+ if (!m_drawable)
+ return;
+
+ Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ const bool syncX = m_pluginDisplay && m_pluginDisplay != display;
+
+ IntRect exposedRect(rect);
+ exposedRect.intersect(frameRect());
+ exposedRect.move(-frameRect().x(), -frameRect().y());
+
+ RefPtr<cairo_surface_t> drawableSurface = adoptRef(cairo_xlib_surface_create(display,
+ m_drawable,
+ m_visual,
+ m_windowRect.width(),
+ m_windowRect.height()));
+
+ if (m_isTransparent) {
+ // If we have a 32 bit drawable and the plugin wants transparency,
+ // we'll clear the exposed area to transparent first. Otherwise,
+ // we'd end up with junk in there from the last paint, or, worse,
+ // uninitialized data.
+ RefPtr<cairo_t> cr = adoptRef(cairo_create(drawableSurface.get()));
+
+ if (!(cairo_surface_get_content(drawableSurface.get()) & CAIRO_CONTENT_ALPHA)) {
+ // Attempt to fake it when we don't have an alpha channel on our
+ // pixmap. If that's not possible, at least clear the window to
+ // avoid drawing artifacts.
+
+ // This Would not work without double buffering, but we always use it.
+ cairo_set_source_surface(cr.get(), cairo_get_group_target(context->platformContext()),
+ -m_windowRect.x(), -m_windowRect.y());
+ cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE);
+ } else
+ cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR);
+
+ cairo_rectangle(cr.get(), exposedRect.x(), exposedRect.y(),
+ exposedRect.width(), exposedRect.height());
+ cairo_fill(cr.get());
+ }
+
+ XEvent xevent;
+ memset(&xevent, 0, sizeof(XEvent));
+ XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
+ exposeEvent.type = GraphicsExpose;
+ exposeEvent.display = display;
+ exposeEvent.drawable = m_drawable;
+ exposeEvent.x = exposedRect.x();
+ exposeEvent.y = exposedRect.y();
+ exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode
+ exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode
+
+ dispatchNPEvent(xevent);
+
+ if (syncX)
+ XSync(m_pluginDisplay, false); // sync changes by plugin
+
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+
+ cairo_set_source_surface(cr, drawableSurface.get(), frameRect().x(), frameRect().y());
+
+ cairo_rectangle(cr,
+ frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y(),
+ exposedRect.width(), exposedRect.height());
+ cairo_clip(cr);
+
+ if (m_isTransparent)
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ else
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr);
+
+ cairo_restore(cr);
+#endif // defined(XP_UNIX)
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent* event)
+{
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+
+ if (m_isWindowed)
+ return;
+
+ if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent)
+ return;
+
+ NPEvent xEvent;
+#if defined(XP_UNIX)
+ initXEvent(&xEvent);
+ GdkEventKey* gdkEvent = event->keyEvent()->gdkEventKey();
+
+ xEvent.type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // KeyPress/Release get unset somewhere
+ xEvent.xkey.root = getRootWindow(m_parentFrame.get());
+ xEvent.xkey.subwindow = 0; // we have no child window
+ xEvent.xkey.time = event->timeStamp();
+ xEvent.xkey.state = gdkEvent->state; // GdkModifierType mirrors xlib state masks
+ xEvent.xkey.keycode = gdkEvent->hardware_keycode;
+ xEvent.xkey.same_screen = true;
+
+ // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window
+ // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not
+ // set to their normal Xserver values. e.g. Key events don't have a position.
+ // source: https://developer.mozilla.org/en/NPEvent
+ xEvent.xkey.x = 0;
+ xEvent.xkey.y = 0;
+ xEvent.xkey.x_root = 0;
+ xEvent.xkey.y_root = 0;
+#endif
+
+ if (!dispatchNPEvent(xEvent))
+ event->setDefaultHandled();
+}
+
+#if defined(XP_UNIX)
+static unsigned int inputEventState(MouseEvent* event)
+{
+ unsigned int state = 0;
+ if (event->ctrlKey())
+ state |= ControlMask;
+ if (event->shiftKey())
+ state |= ShiftMask;
+ if (event->altKey())
+ state |= Mod1Mask;
+ if (event->metaKey())
+ state |= Mod4Mask;
+ return state;
+}
+
+void PluginView::initXEvent(XEvent* xEvent)
+{
+ memset(xEvent, 0, sizeof(XEvent));
+
+ xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server
+ xEvent->xany.send_event = false;
+ xEvent->xany.display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ // NOTE: event->xany.window doesn't always correspond to the .window property of other XEvent's
+ // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify
+ // events; thus, this is right:
+ GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
+ xEvent->xany.window = widget ? GDK_WINDOW_XWINDOW(gtk_widget_get_window(widget)) : 0;
+}
+
+static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
+{
+ XButtonEvent& xbutton = xEvent->xbutton;
+ xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease;
+ xbutton.root = getRootWindow(parentFrame);
+ xbutton.subwindow = 0;
+ xbutton.time = event->timeStamp();
+ xbutton.x = postZoomPos.x();
+ xbutton.y = postZoomPos.y();
+ xbutton.x_root = event->screenX();
+ xbutton.y_root = event->screenY();
+ xbutton.state = inputEventState(event);
+ switch (event->button()) {
+ case MiddleButton:
+ xbutton.button = Button2;
+ break;
+ case RightButton:
+ xbutton.button = Button3;
+ break;
+ case LeftButton:
+ default:
+ xbutton.button = Button1;
+ break;
+ }
+ xbutton.same_screen = true;
+}
+
+static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
+{
+ XMotionEvent& xmotion = xEvent->xmotion;
+ xmotion.type = MotionNotify;
+ xmotion.root = getRootWindow(parentFrame);
+ xmotion.subwindow = 0;
+ xmotion.time = event->timeStamp();
+ xmotion.x = postZoomPos.x();
+ xmotion.y = postZoomPos.y();
+ xmotion.x_root = event->screenX();
+ xmotion.y_root = event->screenY();
+ xmotion.state = inputEventState(event);
+ xmotion.is_hint = NotifyNormal;
+ xmotion.same_screen = true;
+}
+
+static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame)
+{
+ XCrossingEvent& xcrossing = xEvent->xcrossing;
+ xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify;
+ xcrossing.root = getRootWindow(parentFrame);
+ xcrossing.subwindow = 0;
+ xcrossing.time = event->timeStamp();
+ xcrossing.x = postZoomPos.y();
+ xcrossing.y = postZoomPos.x();
+ xcrossing.x_root = event->screenX();
+ xcrossing.y_root = event->screenY();
+ xcrossing.state = inputEventState(event);
+ xcrossing.mode = NotifyNormal;
+ xcrossing.detail = NotifyDetailNone;
+ xcrossing.same_screen = true;
+ xcrossing.focus = false;
+}
+#endif
+
+void PluginView::handleMouseEvent(MouseEvent* event)
+{
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+
+ if (m_isWindowed)
+ return;
+
+ if (event->type() == eventNames().mousedownEvent) {
+ if (Page* page = m_parentFrame->page())
+ page->focusController()->setActive(true);
+ focusPluginElement();
+ }
+
+ NPEvent xEvent;
+#if defined(XP_UNIX)
+ initXEvent(&xEvent);
+
+ IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation()));
+
+ if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
+ setXButtonEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
+ else if (event->type() == eventNames().mousemoveEvent)
+ setXMotionEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
+ else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent)
+ setXCrossingEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get());
+ else
+ return;
+#endif
+
+ if (!dispatchNPEvent(xEvent))
+ event->setDefaultHandled();
+}
+
+#if defined(XP_UNIX)
+void PluginView::handleFocusInEvent()
+{
+ XEvent npEvent;
+ initXEvent(&npEvent);
+
+ XFocusChangeEvent& event = npEvent.xfocus;
+ event.type = 9; // FocusIn gets unset somewhere
+ event.mode = NotifyNormal;
+ event.detail = NotifyDetailNone;
+
+ dispatchNPEvent(npEvent);
+}
+
+void PluginView::handleFocusOutEvent()
+{
+ XEvent npEvent;
+ initXEvent(&npEvent);
+
+ XFocusChangeEvent& event = npEvent.xfocus;
+ event.type = 10; // FocusOut gets unset somewhere
+ event.mode = NotifyNormal;
+ event.detail = NotifyDetailNone;
+
+ dispatchNPEvent(npEvent);
+}
+#endif
+
+void PluginView::setParent(ScrollView* parent)
+{
+ Widget::setParent(parent);
+
+ if (parent)
+ init();
+}
+
+void PluginView::setNPWindowRect(const IntRect&)
+{
+ if (!m_isWindowed)
+ setNPWindowIfNeeded();
+}
+
+void PluginView::setNPWindowIfNeeded()
+{
+ if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow)
+ return;
+
+ // If the plugin didn't load sucessfully, no point in calling setwindow
+ if (m_status != PluginStatusLoadedSuccessfully)
+ return;
+
+ // On Unix, only call plugin's setwindow if it's full-page or windowed
+ if (m_mode != NP_FULL && m_mode != NP_EMBED)
+ return;
+
+ // Check if the platformPluginWidget still exists
+ if (m_isWindowed && !platformPluginWidget())
+ return;
+
+ if (m_isWindowed) {
+ m_npWindow.x = m_windowRect.x();
+ m_npWindow.y = m_windowRect.y();
+ m_npWindow.width = m_windowRect.width();
+ m_npWindow.height = m_windowRect.height();
+
+ m_npWindow.clipRect.left = max(0, m_clipRect.x());
+ m_npWindow.clipRect.top = max(0, m_clipRect.y());
+ m_npWindow.clipRect.right = m_clipRect.x() + m_clipRect.width();
+ m_npWindow.clipRect.bottom = m_clipRect.y() + m_clipRect.height();
+ } else {
+ m_npWindow.x = 0;
+ m_npWindow.y = 0;
+ m_npWindow.width = m_windowRect.width();
+ m_npWindow.height = m_windowRect.height();
+
+ m_npWindow.clipRect.left = 0;
+ m_npWindow.clipRect.top = 0;
+ m_npWindow.clipRect.right = 0;
+ m_npWindow.clipRect.bottom = 0;
+ }
+
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+
+ if (m_isWindowed) {
+ GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() };
+ gtk_widget_size_allocate(platformPluginWidget(), &allocation);
+#if defined(XP_UNIX)
+ if (!m_needsXEmbed) {
+ gtk_xtbin_set_position(GTK_XTBIN(platformPluginWidget()), m_windowRect.x(), m_windowRect.y());
+ gtk_xtbin_resize(platformPluginWidget(), m_windowRect.width(), m_windowRect.height());
+ }
+#endif
+ }
+}
+
+void PluginView::setParentVisible(bool visible)
+{
+ if (isParentVisible() == visible)
+ return;
+
+ Widget::setParentVisible(visible);
+
+ if (isSelfVisible() && platformPluginWidget()) {
+ if (visible)
+ gtk_widget_show(platformPluginWidget());
+ else
+ gtk_widget_hide(platformPluginWidget());
+ }
+}
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
+{
+ WTF::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;
+}
+
+bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVToolkit:
+#if defined(XP_UNIX)
+ *static_cast<uint32_t*>(value) = 2;
+#else
+ *static_cast<uint32_t*>(value) = 0;
+#endif
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVSupportsXEmbedBool:
+#if defined(XP_UNIX)
+ *static_cast<NPBool*>(value) = true;
+#else
+ *static_cast<NPBool*>(value) = false;
+#endif
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVjavascriptEnabledBool:
+ *static_cast<NPBool*>(value) = true;
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ case NPNVSupportsWindowless:
+#if defined(XP_UNIX)
+ *static_cast<NPBool*>(value) = true;
+#else
+ *static_cast<NPBool*>(value) = false;
+#endif
+ *result = NPERR_NO_ERROR;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
+{
+ switch (variable) {
+ case NPNVxDisplay:
+#if defined(XP_UNIX)
+ if (m_needsXEmbed)
+ *(void **)value = (void *)GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ else
+ *(void **)value = (void *)GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay;
+ *result = NPERR_NO_ERROR;
+#else
+ *result = NPERR_GENERIC_ERROR;
+#endif
+ return true;
+
+#if defined(XP_UNIX)
+ case NPNVxtAppContext:
+ if (!m_needsXEmbed) {
+ *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay);
+
+ *result = NPERR_NO_ERROR;
+ } else
+ *result = NPERR_GENERIC_ERROR;
+ return true;
+#endif
+
+ case NPNVnetscapeWindow: {
+#if defined(XP_UNIX)
+ void* w = reinterpret_cast<void*>(value);
+ GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
+ *((XID *)w) = GDK_WINDOW_XWINDOW(gtk_widget_get_window(widget));
+#endif
+#ifdef GDK_WINDOWING_WIN32
+ HGDIOBJ* w = reinterpret_cast<HGDIOBJ*>(value);
+ GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient();
+ *w = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
+#endif
+ *result = NPERR_NO_ERROR;
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+void PluginView::invalidateRect(const IntRect& rect)
+{
+ if (m_isWindowed) {
+ gtk_widget_queue_draw_area(GTK_WIDGET(platformPluginWidget()), rect.x(), rect.y(), rect.width(), rect.height());
+ return;
+ }
+
+ invalidateWindowlessPluginRect(rect);
+}
+
+void PluginView::invalidateRect(NPRect* rect)
+{
+ if (!rect) {
+ invalidate();
+ return;
+ }
+
+ IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
+ invalidateWindowlessPluginRect(r);
+}
+
+void PluginView::invalidateRegion(NPRegion)
+{
+ // TODO: optimize
+ invalidate();
+}
+
+void PluginView::forceRedraw()
+{
+ if (m_isWindowed)
+ gtk_widget_queue_draw(platformPluginWidget());
+ else
+ gtk_widget_queue_draw(m_parentFrame->view()->hostWindow()->platformPageClient());
+}
+
+static Display* getPluginDisplay()
+{
+ // The plugin toolkit might have a different X connection open. Since we're
+ // a gdk/gtk app, we'll (probably?) have the same X connection as any gdk-based
+ // plugins, so we can return that. We might want to add other implementations here
+ // later.
+
+#if defined(XP_UNIX)
+ return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+#else
+ return 0;
+#endif
+}
+
+#if defined(XP_UNIX)
+static void getVisualAndColormap(int depth, Visual** visual, Colormap* colormap)
+{
+ *visual = 0;
+ *colormap = 0;
+
+ Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ int rmaj, rmin;
+ if (depth == 32 && (!XRenderQueryVersion(display, &rmaj, &rmin) || (rmaj == 0 && rmin < 5)))
+ return;
+
+ XVisualInfo templ;
+ templ.screen = gdk_screen_get_number(gdk_screen_get_default());
+ templ.depth = depth;
+ templ.c_class = TrueColor;
+ int nVisuals;
+ XVisualInfo* visualInfo = XGetVisualInfo(display, VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nVisuals);
+
+ if (!nVisuals)
+ return;
+
+ if (depth == 32) {
+ for (int idx = 0; idx < nVisuals; ++idx) {
+ XRenderPictFormat* format = XRenderFindVisualFormat(display, visualInfo[idx].visual);
+ if (format->type == PictTypeDirect && format->direct.alphaMask) {
+ *visual = visualInfo[idx].visual;
+ break;
+ }
+ }
+ } else
+ *visual = visualInfo[0].visual;
+
+ XFree(visualInfo);
+
+ if (*visual)
+ *colormap = XCreateColormap(display, GDK_ROOT_WINDOW(), *visual, AllocNone);
+}
+#endif
+
+static gboolean plugRemovedCallback(GtkSocket* socket, gpointer)
+{
+ return TRUE;
+}
+
+static void plugAddedCallback(GtkSocket* socket, PluginView* view)
+{
+ if (!socket || !view)
+ return;
+
+ // FIXME: Java Plugins do not seem to draw themselves properly the
+ // first time unless we do a size-allocate after they have done
+ // the plug operation on their side, which in general does not
+ // happen since we do size-allocates before setting the
+ // NPWindow. Apply this workaround until we figure out a better
+ // solution, if any.
+ IntRect rect = view->frameRect();
+ GtkAllocation allocation = { rect.x(), rect.y(), rect.width(), rect.height() };
+ gtk_widget_size_allocate(GTK_WIDGET(socket), &allocation);
+}
+
+bool PluginView::platformStart()
+{
+ ASSERT(m_isStarted);
+ ASSERT(m_status == PluginStatusLoadedSuccessfully);
+
+ if (m_plugin->pluginFuncs()->getvalue) {
+ PluginView::setCurrentPluginView(this);
+ JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+ setCallingPlugin(true);
+ m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed);
+ setCallingPlugin(false);
+ PluginView::setCurrentPluginView(0);
+ }
+
+ if (m_isWindowed) {
+#if defined(XP_UNIX)
+ GtkWidget* pageClient = m_parentFrame->view()->hostWindow()->platformPageClient();
+
+ if (m_needsXEmbed) {
+ // If our parent is not anchored the startup process will
+ // fail miserably for XEmbed plugins a bit later on when
+ // we try to get the ID of our window (since realize will
+ // fail), so let's just abort here.
+ if (!gtk_widget_get_parent(pageClient))
+ return false;
+
+ setPlatformWidget(gtk_socket_new());
+ gtk_container_add(GTK_CONTAINER(pageClient), platformPluginWidget());
+ g_signal_connect(platformPluginWidget(), "plug-added", G_CALLBACK(plugAddedCallback), this);
+ g_signal_connect(platformPluginWidget(), "plug-removed", G_CALLBACK(plugRemovedCallback), NULL);
+ } else
+ setPlatformWidget(gtk_xtbin_new(pageClient, 0));
+#else
+ setPlatformWidget(gtk_socket_new());
+ gtk_container_add(GTK_CONTAINER(pageClient), platformPluginWidget());
+#endif
+ } else {
+ setPlatformWidget(0);
+ m_pluginDisplay = getPluginDisplay();
+ }
+
+ show();
+
+#if defined(XP_UNIX)
+ NPSetWindowCallbackStruct* ws = new NPSetWindowCallbackStruct();
+ ws->type = 0;
+#endif
+
+ if (m_isWindowed) {
+ m_npWindow.type = NPWindowTypeWindow;
+#if defined(XP_UNIX)
+ if (m_needsXEmbed) {
+ GtkWidget* widget = platformPluginWidget();
+ gtk_widget_realize(widget);
+ m_npWindow.window = (void*)gtk_socket_get_id(GTK_SOCKET(platformPluginWidget()));
+ GdkWindow* window = gtk_widget_get_window(widget);
+ ws->display = GDK_WINDOW_XDISPLAY(window);
+ ws->visual = GDK_VISUAL_XVISUAL(gdk_window_get_visual(window));
+ ws->depth = gdk_visual_get_depth(gdk_window_get_visual(window));
+ ws->colormap = XCreateColormap(ws->display, GDK_ROOT_WINDOW(), ws->visual, AllocNone);
+ } else {
+ m_npWindow.window = (void*)GTK_XTBIN(platformPluginWidget())->xtwindow;
+ ws->display = GTK_XTBIN(platformPluginWidget())->xtdisplay;
+ ws->visual = GTK_XTBIN(platformPluginWidget())->xtclient.xtvisual;
+ ws->depth = GTK_XTBIN(platformPluginWidget())->xtclient.xtdepth;
+ ws->colormap = GTK_XTBIN(platformPluginWidget())->xtclient.xtcolormap;
+ }
+ XFlush (ws->display);
+#elif defined(GDK_WINDOWING_WIN32)
+ m_npWindow.window = (void*)GDK_WINDOW_HWND(gtk_widget_get_window(platformPluginWidget()));
+#endif
+ } else {
+ m_npWindow.type = NPWindowTypeDrawable;
+ m_npWindow.window = 0; // Not used?
+
+#if defined(XP_UNIX)
+ GdkScreen* gscreen = gdk_screen_get_default();
+ GdkVisual* gvisual = gdk_screen_get_system_visual(gscreen);
+
+ if (gdk_visual_get_depth(gvisual) == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) {
+ getVisualAndColormap(32, &m_visual, &m_colormap);
+ ws->depth = 32;
+ }
+
+ if (!m_visual) {
+ getVisualAndColormap(gdk_visual_get_depth(gvisual), &m_visual, &m_colormap);
+ ws->depth = gdk_visual_get_depth(gvisual);
+ }
+
+ ws->display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+ ws->visual = m_visual;
+ ws->colormap = m_colormap;
+
+ m_npWindow.x = 0;
+ m_npWindow.y = 0;
+ m_npWindow.width = -1;
+ m_npWindow.height = -1;
+#else
+ notImplemented();
+ m_status = PluginStatusCanNotLoadPlugin;
+ return false;
+#endif
+ }
+
+#if defined(XP_UNIX)
+ m_npWindow.ws_info = ws;
+#endif
+
+ // TODO remove in favor of null events, like mac port?
+ if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall)))
+ updatePluginWidget(); // was: setNPWindowIfNeeded(), but this doesn't produce 0x0 rects at first go
+
+ return true;
+}
+
+void PluginView::platformDestroy()
+{
+#if defined(XP_UNIX)
+ if (m_drawable) {
+ XFreePixmap(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), m_drawable);
+ m_drawable = 0;
+ }
+#endif
+}
+
+void PluginView::halt()
+{
+}
+
+void PluginView::restart()
+{
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/plugins/gtk/gtk2xtbin.c b/Source/WebCore/plugins/gtk/gtk2xtbin.c
new file mode 100644
index 0000000..e03fad3
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/gtk2xtbin.c
@@ -0,0 +1,966 @@
+/* -*- 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.
+ */
+
+#include "GtkVersioning.h"
+#include "xembed.h"
+#include "gtk2xtbin.h"
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <glib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Xlib/Xt stuff */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Shell.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+/* 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_dispose (GObject *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)
+{
+ 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;
+}
+
+typedef void (*GSourceFuncsFinalize) (GSource* source);
+
+static GSourceFuncs xt_event_funcs = {
+ xt_event_prepare,
+ xt_event_check,
+ xt_event_dispatch,
+ (GSourceFuncsFinalize)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;
+}
+
+GType
+gtk_xtbin_get_type (void)
+{
+ static GType xtbin_type = 0;
+
+ if (!xtbin_type) {
+ static const GTypeInfo xtbin_info =
+ {
+ sizeof (GtkXtBinClass),
+ NULL,
+ NULL,
+
+ (GClassInitFunc)gtk_xtbin_class_init,
+ NULL,
+ NULL,
+
+ sizeof (GtkXtBin),
+ 0,
+ (GInstanceInitFunc)gtk_xtbin_init,
+ NULL
+ };
+ xtbin_type = g_type_register_static (GTK_TYPE_SOCKET,
+ "GtkXtBin",
+ &xtbin_info,
+ 0);
+ }
+ return xtbin_type;
+}
+
+static void
+gtk_xtbin_class_init (GtkXtBinClass *klass)
+{
+ GtkWidgetClass *widget_class;
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ widget_class = GTK_WIDGET_CLASS (klass);
+ widget_class->realize = gtk_xtbin_realize;
+ widget_class->unrealize = gtk_xtbin_unrealize;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = gtk_xtbin_dispose;
+}
+
+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 };
+#if GTK_CHECK_VERSION(2, 18, 0)
+ GtkAllocation widget_allocation;
+#endif
+
+#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 */
+#if GTK_CHECK_VERSION(2, 24, 0)
+ allocation.width = gdk_window_get_width(xtbin->parent_window);
+ allocation.height = gdk_window_get_height(xtbin->parent_window);
+#else
+ gint x, y, w, h, d; /* geometry of window */
+ gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d);
+ allocation.width = w;
+ allocation.height = h;
+#endif
+ gtk_widget_size_allocate (widget, &allocation);
+
+#ifdef DEBUG_XTBIN
+ printf("initial allocation %d %d %d %d\n", x, y, w, h);
+#endif
+
+#if GTK_CHECK_VERSION(2, 18, 0)
+ gtk_widget_get_allocation(widget, &widget_allocation);
+ xtbin->width = widget_allocation.width;
+ xtbin->height = widget_allocation.height;
+#else
+ xtbin->width = widget->allocation.width;
+ xtbin->height = widget->allocation.height;
+#endif
+
+ /* 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 (GtkWidget *parent_widget, String *f)
+{
+ GtkXtBin *xtbin;
+ gpointer user_data;
+ GdkScreen *screen;
+ GdkVisual* visual;
+ Colormap colormap;
+ GdkWindow* parent_window = gtk_widget_get_window(parent_widget);
+
+ assert(parent_window != NULL);
+ xtbin = g_object_new (GTK_TYPE_XTBIN, NULL);
+
+ if (!xtbin)
+ return (GtkWidget*)NULL;
+
+ if (f)
+ fallback = f;
+
+ /* Initialize the Xt toolkit */
+ xtbin->parent_window = parent_window;
+
+ screen = gtk_widget_get_screen(parent_widget);
+ visual = gdk_screen_get_system_visual(screen);
+ colormap = XCreateColormap(GDK_DISPLAY_XDISPLAY(gdk_screen_get_display(screen)),
+ GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(screen)),
+ GDK_VISUAL_XVISUAL(visual), AllocNone);
+
+ xt_client_init(&(xtbin->xtclient),
+ GDK_VISUAL_XVISUAL(visual),
+ colormap,
+ gdk_visual_get_depth(visual));
+
+ 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 =
+ g_timeout_add(25,
+ (GSourceFunc)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_get_realized (GTK_WIDGET(xtbin)))
+ gdk_window_move (gtk_widget_get_window(GTK_WIDGET (xtbin)), 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_set_visible(widget, FALSE);
+ if (gtk_widget_get_realized (widget)) {
+ xt_client_unrealize(&(xtbin->xtclient));
+ }
+
+ (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
+}
+
+static void
+gtk_xtbin_dispose (GObject *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);
+
+ g_source_remove(xt_polling_timer_id);
+ xt_polling_timer_id = 0;
+ }
+ }
+
+ G_OBJECT_CLASS(parent_class)->dispose(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;
+
+ 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)
+{
+ 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<nchildren; ++i) {
+ Widget child = XtWindowToWidget(dpy, children[i]);
+ if (child)
+ xt_add_focus_listener_tree( child, user_data);
+ }
+ XFree((void*)children);
+
+ return;
+}
diff --git a/Source/WebCore/plugins/gtk/gtk2xtbin.h b/Source/WebCore/plugins/gtk/gtk2xtbin.h
new file mode 100644
index 0000000..11f6e06
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/gtk2xtbin.h
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set 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 ***** */
+
+#ifndef __GTK_XTBIN_H__
+#define __GTK_XTBIN_H__
+
+#include <gtk/gtk.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xutil.h>
+#include <X11/Xlib.h>
+#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) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GTK_TYPE_XTBIN, GtkXtBin))
+#define GTK_XTBIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ GTK_TYPE_XTBIN, GtkXtBinClass))
+#define GTK_IS_XTBIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ GTK_TYPE_XTBIN))
+#define GTK_IS_XTBIN_CLASS(klass) (G_TYPE_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(GType) gtk_xtbin_get_type (void);
+GTKXTBIN_API(GtkWidget *) gtk_xtbin_new (GtkWidget *parent_widget, 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/Source/WebCore/plugins/gtk/xembed.h b/Source/WebCore/plugins/gtk/xembed.h
new file mode 100644
index 0000000..dff7be9
--- /dev/null
+++ b/Source/WebCore/plugins/gtk/xembed.h
@@ -0,0 +1,64 @@
+/* -*- 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)