/* | |
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); | |
} |