WebCore/plugins/qt/PluginContainerQt.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/plugins/qt/PluginContainerQt.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,150 @@
+/*
+    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+    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 "PluginContainerQt.h"
+
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "PluginView.h"
+#include <QApplication>
+#include <QX11Info>
+
+using namespace WebCore;
+
+PluginClientWrapper::PluginClientWrapper(QWidget* parent, WId client)
+    : QWidget(0, Qt::Popup)
+{
+    // create a QWidget that adopts the plugin window id, do not give it
+    // a parent so that we don't end up handling events supposed to be
+    // handled by the QX11EmbedContainer.
+
+    // without the parent this will be considered a toplevel widget,
+    // and thus make Qt not quit the event loop after the last window
+    // has been closed. In order to work around this, we set the window
+    // type to Qt::Popup.
+
+    create(client, false, true);
+    m_parent = parent;
+}
+
+PluginClientWrapper::~PluginClientWrapper()
+{
+    destroy(false, false);
+}
+
+bool PluginClientWrapper::x11Event(XEvent* event)
+{
+    // modify the event window id and insert it into the Qt event system.
+    event->xany.window = m_parent->parentWidget()->winId();
+    static_cast<QApplication*>(QApplication::instance())->x11ProcessEvent(event);
+    return true;
+}
+
+PluginContainerQt::PluginContainerQt(PluginView* view, QWidget* parent)
+    : QX11EmbedContainer(parent)
+    , m_pluginView(view)
+    , m_clientWrapper(0)
+{
+    connect(this, SIGNAL(clientClosed()), this, SLOT(on_clientClosed()));
+    connect(this, SIGNAL(clientIsEmbedded()), this, SLOT(on_clientIsEmbedded()));
+}
+
+PluginContainerQt::~PluginContainerQt()
+{
+    delete m_clientWrapper;
+    m_pluginView->setPlatformPluginWidget(0);
+}
+
+void PluginContainerQt::on_clientClosed()
+{
+    delete m_clientWrapper;
+    m_clientWrapper = 0;
+}
+
+void PluginContainerQt::on_clientIsEmbedded()
+{
+    delete m_clientWrapper;
+    m_clientWrapper = 0;
+
+    // Only create a QWidget wrapper for the plugin in the case it isn't in the
+    // Qt window mapper, and thus receiving events from the Qt event system.
+    // This way the PluginClientWrapper receives the scroll events and passes
+    // them to the parent. NOTICE: Native Qt based plugins running in process,
+    // will already be in the window mapper, and thus creating a wrapper, stops
+    // them from getting events from Qt, as they are redirected to the wrapper.
+    if (!QWidget::find(clientWinId()))
+        m_clientWrapper = new PluginClientWrapper(this, clientWinId());
+}
+
+void PluginContainerQt::redirectWheelEventsToParent(bool enable)
+{
+    // steal wheel events from the plugin as we want to handle it. When doing this
+    // all button 4, 5, 6, and 7, ButtonPress and ButtonRelease events are passed
+    // to the x11Event handler of the PluginClientWrapper, which then changes the
+    // window id of the event to the parent of PluginContainer and puts the event
+    // back into the Qt event loop, so that we will actually scroll the parent
+    // frame.
+    for (int buttonNo = 4; buttonNo < 8; buttonNo++) {
+        if (enable)
+            XGrabButton(x11Info().display(), buttonNo, AnyModifier, clientWinId(),
+                false, ButtonPressMask, GrabModeAsync, GrabModeAsync, 0L, 0L);
+        else
+            XUngrabButton(x11Info().display(), buttonNo, AnyModifier, clientWinId());
+    }
+}
+
+bool PluginContainerQt::x11Event(XEvent* event)
+{
+    switch (event->type) {
+    case EnterNotify:
+        // if the plugin window doesn't have focus we do not want to send wheel
+        // events to it, but to the parent frame, so let's redirect here.
+        redirectWheelEventsToParent(!hasFocus());
+        break;
+    case LeaveNotify:
+        // it is always safe to ungrab wheel events when the mouse leaves the
+        // plugin window.
+        redirectWheelEventsToParent(false);
+        break;
+    }
+
+    return QX11EmbedContainer::x11Event(event);
+}
+
+void PluginContainerQt::focusInEvent(QFocusEvent* event)
+{
+    // we got focus, stop redirecting the wheel events
+    redirectWheelEventsToParent(false);
+
+    if (Page* page = m_pluginView->parentFrame()->page())
+        page->focusController()->setActive(true);
+
+    m_pluginView->focusPluginElement();
+}
+
+void PluginContainerQt::focusOutEvent(QFocusEvent*)
+{
+    if (Page* page = m_pluginView->parentFrame()->page())
+        page->focusController()->setActive(false);
+}